Example example_splitpackage_automatic-modules
Part of the full Java 9 Jigsaw modules example suite.
|
Authors
Originally written by Martin Lehmann, Kristine Schaal and RĂ¼diger Grammes (cf. original repository). 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
-
modmainis a normal, explicit module, which requires an automatic modulemodauto1 -
modauto1is a automatic module. It has a packagepkgsplitted. -
modauto2is a automatic module. It has a packagepkgsplitted, too.
Module Dependency Graph, created with DepVis
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
modauto1andmodauto2, 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
modmaincan be compiled. - Solution
-
Hybrid compilation approach in
m4/compile.sh:-
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.
-
Maven compiles explicit module (modmain) with compiler argument:
-
--module-path ${project.basedir}/amlib1- makes modauto1 available during compilation
-
-
Runtime uses
--module-path mlib:amlib1to 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