Example example_layer-modules-grouped-in-hierarchy
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 is the same as this example. The main difference is, that the modules are not all in the boot layer but distributed over a layer hierarchy of the boot layers and 3 child layers.
Layers in this example
We have the boot layer as the parent layer for these three child layers:
-
foo layer #1which contains the modulemodfoowhich requires the automatic modulemodauto1 -
bar layer #1which contains the modulemodbarwhich requires the automatic modulemodauto2 -
bar layer #2which contains the modulemodbarwhich requires the automatic modulemodauto2
The boot layer contains these modules
-
modcommonwhich has standard functionality used by all other modules -
modmainwhich does reflective calls tomodbarandmodfoo
Module Dependency Graph, created with DepVis
Note that this graph has been changed manually as DepVis cannot deal with layers for now.
Example shows …
The examples shows what happens, if modmain/pkgmain.Main does reflective calls to classes in module modfoo or modbar, respectively.
Note that these reflective calls from modmain to modfoo and modbar are done from the boot layer to one of its child layers.
More remarks:
-
Reflective calls from the parent layer (from
modmaintomodfooandmodbar) are possible. -
Reflective calls from the parent layer (
modfooandmodbartomodcommon) would also be possible. -
modcommonis used frommodmainandmodfooandmodbar. So it is resolved in the boot layer already. -
The child layers do not have a split package problem, though in
bar layer #1andbar layer #2the same modulemodbaris resolved. -
Also
modbarandmodfoocan use different version of the automatic modulemodauto1|2. No split package problem.
The interesting parts are all done in modmain/pkgmain.Main here in this example.
See its functionality on
-
… how to create child layers and add modules
-
… how to call functionality in child layers
You might also want to look at the differences between modmain/pkgmain.Main here in this example and
modmain/pkgmain.Main in example_layer-modules-all-in-boot-layer.
Output
This example uses golden master testing to ensure output consistency.
The expected output is compared with actual output using verify.sh.
Expected Output
Infos for Layer and Module which contain pkgmain.Main, id=ID_Main_19
Layer (java.lang.ModuleLayer), boot layer
Layer's parents: none, as this is the boot layer
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, modcommon, 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, modcommon, modmain
Create a new 'foo layer #1' as a child of the current layer...
Reflective call to pkgfoo.Foo in modfoo in 'foo layer #1'...
Infos for Layer and Module which contain pkgfoo.Foo, id=ID_Main_74, using automatic module version V1
Layer (java.lang.ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's list of modules:
modauto1, modfoo
Layer's configuration with its list of resolved modules:
modauto1, modfoo
pkgfoo.Foo, id=ID_Main_74, using automatic module version V1
Create a new 'bar layer #1' as a child of the current layer...
Reflective call to pkgbar.Bar in modbar in 'bar layer #1'...
Infos for Layer and Module which contain pkgbar.Bar, id=ID_Main_74, using automatic module version V2
Layer (java.lang.ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's list of modules:
modauto2, modbar
Layer's configuration with its list of resolved modules:
modauto2, modbar
pkgbar.Bar, id=ID_Main_74, using automatic module version V2
Create a new 'bar layer #2' as a child of the current layer...
Reflective call to pkgbar.Bar in modbar in 'bar layer #2'...
Infos for Layer and Module which contain pkgbar.Bar, id=ID_Main_74, using automatic module version V2
Layer (java.lang.ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's list of modules:
modauto2, modbar
Layer's configuration with its list of resolved modules:
modauto2, modbar
pkgbar.Bar, id=ID_Main_74, using automatic module version V2
Actual Output
Infos for Layer and Module which contain pkgmain.Main, id=ID_Main_19
Layer (java.lang.ModuleLayer), boot layer
Layer's parents: none, as this is the boot layer
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, modcommon, 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, modcommon, modmain
Create a new 'foo layer #1' as a child of the current layer...
Reflective call to pkgfoo.Foo in modfoo in 'foo layer #1'...
Infos for Layer and Module which contain pkgfoo.Foo, id=ID_Main_74, using automatic module version V1
Layer (java.lang.ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's list of modules:
modauto1, modfoo
Layer's configuration with its list of resolved modules:
modauto1, modfoo
pkgfoo.Foo, id=ID_Main_74, using automatic module version V1
Create a new 'bar layer #1' as a child of the current layer...
Reflective call to pkgbar.Bar in modbar in 'bar layer #1'...
Infos for Layer and Module which contain pkgbar.Bar, id=ID_Main_74, using automatic module version V2
Layer (java.lang.ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's list of modules:
modauto2, modbar
Layer's configuration with its list of resolved modules:
modauto2, modbar
pkgbar.Bar, id=ID_Main_74, using automatic module version V2
Create a new 'bar layer #2' as a child of the current layer...
Reflective call to pkgbar.Bar in modbar in 'bar layer #2'...
Infos for Layer and Module which contain pkgbar.Bar, id=ID_Main_74, using automatic module version V2
Layer (java.lang.ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's list of modules:
modauto2, modbar
Layer's configuration with its list of resolved modules:
modauto2, modbar
pkgbar.Bar, id=ID_Main_74, using automatic module version V2
Maven 4 Output
Infos for Layer and Module which contain pkgmain.Main, id=ID_Main_19
Layer (java.lang.ModuleLayer), boot layer
Layer's parents: none, as this is the boot layer
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, modcommon, 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, modcommon, modmain
Create a new 'foo layer #1' as a child of the current layer...
Reflective call to pkgfoo.Foo in modfoo in 'foo layer #1'...
Infos for Layer and Module which contain pkgfoo.Foo, id=ID_Main_74, using automatic module version V1
Layer (java.lang.ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's list of modules:
modauto1, modfoo
Layer's configuration with its list of resolved modules:
modauto1, modfoo
pkgfoo.Foo, id=ID_Main_74, using automatic module version V1
Create a new 'bar layer #1' as a child of the current layer...
Reflective call to pkgbar.Bar in modbar in 'bar layer #1'...
Infos for Layer and Module which contain pkgbar.Bar, id=ID_Main_74, using automatic module version V2
Layer (java.lang.ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's list of modules:
modauto2, modbar
Layer's configuration with its list of resolved modules:
modauto2, modbar
pkgbar.Bar, id=ID_Main_74, using automatic module version V2
Create a new 'bar layer #2' as a child of the current layer...
Reflective call to pkgbar.Bar in modbar in 'bar layer #2'...
Infos for Layer and Module which contain pkgbar.Bar, id=ID_Main_74, using automatic module version V2
Layer (java.lang.ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's list of modules:
modauto2, modbar
Layer's configuration with its list of resolved modules:
modauto2, modbar
pkgbar.Bar, id=ID_Main_74, using automatic module version V2
Maven 4 Migration
This example required a special migration approach due to the presence of automatic modules with split packages and module-specific dependencies.
Standard Migration
The base modules (modcommon, modmain) were migrated using the standard Module Source Hierarchy approach with direct paths to the original source directories.
Special Handling: Automatic Modules with Split Packages
- 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.Additionally:
-
Both automatic modules have split packages (
pkgversion) which conflict at compile-time -
modfoorequiresmodauto1whilemodbarrequiresmodauto2 -
Maven 4 compiles all modules together with the same
--module-path, causing split package conflictsThe original approach compiles each explicit module separately with different module-path settings to avoid conflicts.
-
- Solution
-
Hybrid compilation approach in
m4/compile.sh:-
Manual javac compilation of modauto1 → amlib1/ and modauto2 → amlib2/
Each automatic module is compiled separately and packaged as a JAR without module-info.java.
-
Maven compiles base modules (modcommon, modmain) without automatic modules on path
These modules don’t depend on the automatic modules.
-
Manual javac compilation of modfoo with
--module-path mlib:amlib1Only modauto1 is on module-path, avoiding split package conflicts.
-
Manual javac compilation of modbar with
--module-path mlib:amlib2Only modauto2 is on module-path, avoiding split package conflicts.
-
Runtime uses only mlib/ (automatic modules not needed at runtime for this example)
-
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
-
Split packages between automatic modules prevent compiling all modules together
-
Each module requiring an automatic module must be compiled separately with only the needed automatic module on path
-
This example demonstrates module layers where different modules use different automatic module versions
Module-Path Access via mlib for Dynamic Module Loading
The Java code in modmain/pkgmain/Main.java uses the ModuleLayer API to dynamically load modules at runtime from hardcoded paths:
// Dynamically creates layers and loads modules from ./foomlib and ./barmlib
Module fooModule = fooLayer.findModule("modfoo").get();
Module barModule = barLayer.findModule("modbar").get();
Maven (4) creates JARs in the target/ directory with classifier-based names:
target/example_layer-modules-grouped-in-hierarchy-m4-1.0-SNAPSHOT-modcommon.jar
target/example_layer-modules-grouped-in-hierarchy-m4-1.0-SNAPSHOT-modmain.jar
...
To maintain compatibility with the shared Java source code that references mlib, the run.sh script creates mlib using OS-specific approaches:
- Unix/macOS
-
Creates symlink
mlib → target(usingln -sfn) - Windows
-
Creates directory
mlib/and copies JARs fromtarget/
The Windows approach avoids AccessDeniedException issues when Java’s ModuleLayer API traverses symlinks.
|
A committed symlink |