Example example_splitpackage_automatic-modules

Part of the full Java 9 Jigsaw modules example suite.

Authors

Migrated for Java Modules support documentation of Apache MavenTM in the course of the Maven Support & Care program by Gerd Aschemann (and other team members) as forked repository. Please add discussions, requirements, bugfixes, etc. to the fork instead of the original.

What is this example about?

This example shows that automatic modules might cause an unwanted and surprising 'split package' problem.

Modules in this example

  • modmain is a normal, explicit module, which requires an automatic module modauto1

  • modauto1 is a automatic module. It has a package pkgsplitted.

  • modauto2 is a automatic module. It has a package pkgsplitted, too.

Module Dependency Graph, created with DepVis

Example’s Module Dependency Graph

Example shows …​

As soon as one automatic module modauto1 is required (by modmain), it is added to the runtime configuration. All works fine, when only the module path amlib1 with modauto1 is added to the java launcher’s module path, see run.sh.

But as soon as we add amlib2 to the runtime (see run_with-extended-module-path.sh) we add modauto2 to the configuration, though modmain does not require it: Because automatic modules read all other modules, they also read automatically all other automatic modules, so in our example modauto1 reads modauto2. With that, both modauto1 and modauto2 are added to the configuration and as both modules share the same package we this results in a split package problem.

So even though noone (statically) requires modauto2, it is automatically required by modauto1 at runtime and hence causes a runtime error, which might be a bit surprising.

Output

This example uses golden master testing to ensure output consistency. The expected output is compared with actual output using verify.sh.

Expected Output

Hello World from pkgmain.Main
Layer's list of modules:
java.base, java.compiler, java.datatransfer, java.desktop, java.logging, java.management, java.management.rmi, java.naming, java.prefs, java.rmi, java.security.jgss, java.security.sasl, java.smartcardio, java.xml, java.xml.crypto, jdk.charsets, jdk.compiler, jdk.crypto.cryptoki, jdk.crypto.ec, jdk.internal.opt, jdk.jartool, jdk.javadoc, jdk.jdeps, jdk.jfr, jdk.jlink, jdk.localedata, jdk.management, jdk.management.jfr, jdk.naming.dns, jdk.naming.rmi, jdk.security.auth, jdk.security.jgss, jdk.unsupported.desktop, jdk.zipfs, modauto1, modmain

Layer's configuration with its list of resolved modules:
java.base, java.compiler, java.datatransfer, java.desktop, java.logging, java.management, java.management.rmi, java.naming, java.prefs, java.rmi, java.security.jgss, java.security.sasl, java.smartcardio, java.xml, java.xml.crypto, jdk.charsets, jdk.compiler, jdk.crypto.cryptoki, jdk.crypto.ec, jdk.internal.opt, jdk.jartool, jdk.javadoc, jdk.jdeps, jdk.jfr, jdk.jlink, jdk.localedata, jdk.management, jdk.management.jfr, jdk.naming.dns, jdk.naming.rmi, jdk.security.auth, jdk.security.jgss, jdk.unsupported.desktop, jdk.zipfs, modauto1, modmain

Actual Output

Hello World from pkgmain.Main
Layer's list of modules:
java.base, java.compiler, java.datatransfer, java.desktop, java.logging, java.management, java.management.rmi, java.naming, java.prefs, java.rmi, java.security.jgss, java.security.sasl, java.smartcardio, java.xml, java.xml.crypto, jdk.charsets, jdk.compiler, jdk.crypto.cryptoki, jdk.crypto.ec, jdk.internal.opt, jdk.jartool, jdk.javadoc, jdk.jdeps, jdk.jfr, jdk.jlink, jdk.localedata, jdk.management, jdk.management.jfr, jdk.naming.dns, jdk.naming.rmi, jdk.security.auth, jdk.security.jgss, jdk.unsupported.desktop, jdk.zipfs, modauto1, modmain

Layer's configuration with its list of resolved modules:
java.base, java.compiler, java.datatransfer, java.desktop, java.logging, java.management, java.management.rmi, java.naming, java.prefs, java.rmi, java.security.jgss, java.security.sasl, java.smartcardio, java.xml, java.xml.crypto, jdk.charsets, jdk.compiler, jdk.crypto.cryptoki, jdk.crypto.ec, jdk.internal.opt, jdk.jartool, jdk.javadoc, jdk.jdeps, jdk.jfr, jdk.jlink, jdk.localedata, jdk.management, jdk.management.jfr, jdk.naming.dns, jdk.naming.rmi, jdk.security.auth, jdk.security.jgss, jdk.unsupported.desktop, jdk.zipfs, modauto1, modmain

Maven 4 Output

Hello World from pkgmain.Main
Layer's list of modules:
java.base, java.compiler, java.datatransfer, java.desktop, java.logging, java.management, java.management.rmi, java.naming, java.prefs, java.rmi, java.security.jgss, java.security.sasl, java.smartcardio, java.xml, java.xml.crypto, jdk.charsets, jdk.compiler, jdk.crypto.cryptoki, jdk.crypto.ec, jdk.internal.opt, jdk.jartool, jdk.javadoc, jdk.jdeps, jdk.jfr, jdk.jlink, jdk.localedata, jdk.management, jdk.management.jfr, jdk.naming.dns, jdk.naming.rmi, jdk.security.auth, jdk.security.jgss, jdk.unsupported.desktop, jdk.zipfs, modauto1, modmain

Layer's configuration with its list of resolved modules:
java.base, java.compiler, java.datatransfer, java.desktop, java.logging, java.management, java.management.rmi, java.naming, java.prefs, java.rmi, java.security.jgss, java.security.sasl, java.smartcardio, java.xml, java.xml.crypto, jdk.charsets, jdk.compiler, jdk.crypto.cryptoki, jdk.crypto.ec, jdk.internal.opt, jdk.jartool, jdk.javadoc, jdk.jdeps, jdk.jfr, jdk.jlink, jdk.localedata, jdk.management, jdk.management.jfr, jdk.naming.dns, jdk.naming.rmi, jdk.security.auth, jdk.security.jgss, jdk.unsupported.desktop, jdk.zipfs, modauto1, modmain

Maven 4 Migration

This example required a special migration approach due to the presence of automatic modules (modules without module-info.java).

Standard Migration

The explicit module (modmain) was migrated using the standard Module Source Hierarchy approach with direct path to the original source directory.

Special Handling: Automatic Modules

Problem

Maven 4’s Module Source Hierarchy requires module descriptors (module-info.java) for all source entries. This example contains modauto1 and modauto2, which are automatic modules without module-info.java.

Automatic modules must be compiled as ordinary JAR files (without module-info.java) and placed on the module-path before modmain can be compiled.

Solution

Hybrid compilation approach in m4/compile.sh:

  1. Manual javac compilation of modauto1 and modauto2 to amlib1/ and amlib2/

    Each automatic module is compiled separately and packaged as a JAR without module-info.java.

  2. Maven compiles explicit module (modmain) with compiler argument:

    • --module-path ${project.basedir}/amlib1 - makes modauto1 available during compilation

  3. Runtime uses --module-path mlib:amlib1 to include both explicit modules and automatic modules

This hybrid approach is necessary because:

  • Maven 4’s Module Source Hierarchy cannot compile code without module-info.java

  • Automatic modules must be compiled and packaged before explicit modules that depend on them

  • This example demonstrates split package issues between automatic modules

  • Only modauto1 is placed on the module-path at runtime to avoid split package conflicts