Example example_layer-modules-before-finder
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 similar to this example. It shows how a module from the boot layer can be overwritten in a child layer depending on the order of resolution.
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 modulesmodversion1andmodcommon -
bar layer #1which contains the modulemodbarwhich requires the modulesmodversion2andmodcommon -
bar layer #2which contains the modulemodbarwhich requires the modulesmodversion2andmodcommon
The boot layer contains these modules (from mlib/)
-
modcommonwhich has standard functionality used by all other modules -
modmainwhich does reflective calls tomodbarandmodfoo
The foo layer contains these modules (from foomlib/)
-
modversion1which produces the version string "V1" -
modfoowhich prints its id and the version from modversion1
The bar layers contains these modules (from barmlib/)
-
modcommon, a new version of modcommon found in boot layer. It prints certain texts in blue colour on ANSI terminals. -
modversion2which produces the version string "V2" -
modbarwhich prints its id and the version from modversion2
Example shows …
This exampe shows how modcommon is resolved differently depending on how a layer is created:
-
modmain resolves modcommon from the module path (mlib/), both end up in the boot layer on startup.
-
modfoo is placed in the newly created foo-layer together with modversion1. Its "module path" foomlib/ does not contain modcommon so it is resolved from the boot layer.
-
modbar is placed in the newly created bar-layer #1 together with modversion2. barmlib/ does contain a new version of modcommon, however, the boot layer version is found first and is thus used.
-
modbar is again played in the newly created bar-layer #2 together with modversion2. This time, we create the layer putting barmlib/ in the so-called "before"-ModuleFinder. Now the new version of modcommon is resolved instead, and we see blue output on ANSI terminals when this version of modbar is called.
Note that using automatic modules in either bar-layer #1 or #2 will lead to failure. An automatic module will try to add reads dependencies to all modules in the bar-layer and in the parent boot layer. In doing this, it tries to read from both modcommon in boot as well as modcommon in bar! This leads to a module resolution error.
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:
Layer (ModuleLayer), boot layer
Layer's parents: none, as this is the boot layer
Layer's configuration including read dependencies:
[31mjava.base@11.0.28 (Configuration)[0m -> [], [31mjava.compiler@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mjava.datatransfer@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mjava.desktop@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.datatransfer@11.0.28 (Configuration), java.prefs@11.0.28 (Configuration), java.xml@11.0.28 (Configuration)], [31mjava.logging@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mjava.management.rmi@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.management@11.0.28 (Configuration), java.naming@11.0.28 (Configuration), java.rmi@11.0.28 (Configuration)], [31mjava.management@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mjava.naming@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.security.sasl@11.0.28 (Configuration)], [31mjava.prefs@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.xml@11.0.28 (Configuration)], [31mjava.rmi@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.logging@11.0.28 (Configuration)], [31mjava.security.jgss@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.naming@11.0.28 (Configuration)], [31mjava.security.sasl@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.logging@11.0.28 (Configuration)], [31mjava.smartcardio@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mjava.xml.crypto@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.logging@11.0.28 (Configuration), java.xml@11.0.28 (Configuration)], [31mjava.xml@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mmodcommon@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mmodmain@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration), modcommon@1.0 (Configuration)]
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:
Layer (ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's configuration including read dependencies:
[31mmodfoo@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration), modcommon@1.0 (Configuration), modversion1@1.0 (Configuration)], [31mmodversion1@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration)]
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:
Layer (ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's configuration including read dependencies:
[31mmodbar@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration), modcommon@1.0 (Configuration), modversion2@1.0 (Configuration)], [31mmodversion2@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration)]
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:
Layer (ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's configuration including read dependencies:
[31mmodbar@1.0[0m (Configuration) -> [[34mjava.base@11.0.28[0m (Configuration), [34mmodcommon@2.0[0m (Configuration), [34mmodversion2@1.0[0m (Configuration)], [31mmodcommon@2.0[0m (Configuration) -> [[34mjava.base@11.0.28[0m (Configuration)], [31mmodversion2@1.0[0m (Configuration) -> [[34mjava.base@11.0.28[0m (Configuration)]
pkgbar.Bar, id=ID_Main_74, using automatic module version V2
Actual Output
Infos for Layer and Module:
Layer (ModuleLayer), boot layer
Layer's parents: none, as this is the boot layer
Layer's configuration including read dependencies:
[31mjava.base@11.0.28 (Configuration)[0m -> [], [31mjava.compiler@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mjava.datatransfer@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mjava.desktop@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.datatransfer@11.0.28 (Configuration), java.prefs@11.0.28 (Configuration), java.xml@11.0.28 (Configuration)], [31mjava.logging@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mjava.management.rmi@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.management@11.0.28 (Configuration), java.naming@11.0.28 (Configuration), java.rmi@11.0.28 (Configuration)], [31mjava.management@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mjava.naming@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.security.sasl@11.0.28 (Configuration)], [31mjava.prefs@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.xml@11.0.28 (Configuration)], [31mjava.rmi@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.logging@11.0.28 (Configuration)], [31mjava.security.jgss@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.naming@11.0.28 (Configuration)], [31mjava.security.sasl@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.logging@11.0.28 (Configuration)], [31mjava.smartcardio@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mjava.xml.crypto@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.logging@11.0.28 (Configuration), java.xml@11.0.28 (Configuration)], [31mjava.xml@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mmodcommon@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mmodmain@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration), modcommon@1.0 (Configuration)]
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:
Layer (ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's configuration including read dependencies:
[31mmodfoo@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration), modcommon@1.0 (Configuration), modversion1@1.0 (Configuration)], [31mmodversion1@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration)]
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:
Layer (ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's configuration including read dependencies:
[31mmodbar@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration), modcommon@1.0 (Configuration), modversion2@1.0 (Configuration)], [31mmodversion2@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration)]
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:
Layer (ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's configuration including read dependencies:
[31mmodbar@1.0[0m (Configuration) -> [[34mjava.base@11.0.28[0m (Configuration), [34mmodcommon@2.0[0m (Configuration), [34mmodversion2@1.0[0m (Configuration)], [31mmodcommon@2.0[0m (Configuration) -> [[34mjava.base@11.0.28[0m (Configuration)], [31mmodversion2@1.0[0m (Configuration) -> [[34mjava.base@11.0.28[0m (Configuration)]
pkgbar.Bar, id=ID_Main_74, using automatic module version V2
Maven 4 Output
Infos for Layer and Module:
Layer (ModuleLayer), boot layer
Layer's parents: none, as this is the boot layer
Layer's configuration including read dependencies:
[31mjava.base@11.0.28 (Configuration)[0m -> [], [31mjava.compiler@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mjava.datatransfer@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mjava.desktop@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.datatransfer@11.0.28 (Configuration), java.prefs@11.0.28 (Configuration), java.xml@11.0.28 (Configuration)], [31mjava.logging@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mjava.management.rmi@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.management@11.0.28 (Configuration), java.naming@11.0.28 (Configuration), java.rmi@11.0.28 (Configuration)], [31mjava.management@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mjava.naming@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.security.sasl@11.0.28 (Configuration)], [31mjava.prefs@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.xml@11.0.28 (Configuration)], [31mjava.rmi@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.logging@11.0.28 (Configuration)], [31mjava.security.jgss@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.naming@11.0.28 (Configuration)], [31mjava.security.sasl@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.logging@11.0.28 (Configuration)], [31mjava.smartcardio@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mjava.xml.crypto@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration), java.logging@11.0.28 (Configuration), java.xml@11.0.28 (Configuration)], [31mjava.xml@11.0.28 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mmodcommon@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration)], [31mmodmain@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration), modcommon@1.0 (Configuration)]
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:
Layer (ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's configuration including read dependencies:
[31mmodfoo@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration), modcommon@1.0 (Configuration), modversion1@1.0 (Configuration)], [31mmodversion1@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration)]
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:
Layer (ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's configuration including read dependencies:
[31mmodbar@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration), modcommon@1.0 (Configuration), modversion2@1.0 (Configuration)], [31mmodversion2@1.0 (Configuration)[0m -> [java.base@11.0.28 (Configuration)]
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:
Layer (ModuleLayer), not boot layer
Layer's parents: Parent is boot layer
Layer's configuration including read dependencies:
[31mmodbar@1.0[0m (Configuration) -> [[34mjava.base@11.0.28[0m (Configuration), [34mmodcommon@2.0[0m (Configuration), [34mmodversion2@1.0[0m (Configuration)], [31mmodcommon@2.0[0m (Configuration) -> [[34mjava.base@11.0.28[0m (Configuration)], [31mmodversion2@1.0[0m (Configuration) -> [[34mjava.base@11.0.28[0m (Configuration)]
pkgbar.Bar, id=ID_Main_74, using automatic module version V2
Maven 4 Migration
This example required a special migration approach due to its unique requirement of compiling multiple versions of the same module.
Standard Migration
The primary modules (modbar, modcommon v1.0, modfoo, modmain, modversion1, modversion2) were migrated using the standard Module Source Hierarchy approach documented in the central Maven 4 Migration guide.
Special Handling: Multiple Module Versions
This example demonstrates module layer resolution by using two different versions of modcommon:
-
modcommonv1.0 (fromsrc/modcommon) - used in the boot layer -
modcommonv2.0 (fromsrc2/modcommon) - used in bar layer #2 to demonstrate version overriding- Problem
-
Maven 4’s Module Source Hierarchy cannot handle multiple versions of the same module in a single build. The
<sources>element expects one source location per module name. - Solution
-
Hybrid compilation approach in
m4/compile.sh:
-
Maven compiles all primary modules (modbar, modcommon v1.0, modfoo, modmain, modversion1, modversion2) using Module Source Hierarchy
-
Maven creates JARs in
target/using maven-jar-plugin with classifiers
-
-
The compile script copies layer-specific JARs to their respective directories for dynamic module loading:
# Copy foo layer modules (modfoo, modversion1) to foomlib/ for mod in modfoo modversion1; do cp "target/example_layer-modules-module-resolution-m4-1.0-${mod}.jar" "foomlib/${mod}.jar" done # Copy bar layer modules (modbar, modversion2) to barmlib/ for mod in modbar modversion2; do cp "target/example_layer-modules-module-resolution-m4-1.0-${mod}.jar" "barmlib/${mod}.jar" done -
Manual javac invocation compiles modcommon v2.0 from src2/:
javac -d mods2 --release 11 --module-version=2.0 \ --module-path target --module-source-path ../src2 \ $(find ../src2/modcommon -name "*.java") jar --create --file=../barmlib/modcommon.jar -C modcommon . -
JAR placement for dynamic module loading:
-
target/ - Maven-built JARs (with classifiers)
-
mlib/ - Boot layer modules (OS-specific: Unix uses symlink to target/, Windows uses directory with copied JARs)
-
foomlib/ - foo layer modules (modfoo, modversion1) copied from target/
-
barmlib/ - bar layer modules (modbar, modversion2) copied from target/, plus modcommon v2.0 compiled manually
The
run.shscript createsmlibusing OS-specific approaches to avoidAccessDeniedExceptionwhen Java’sModuleLayerAPI traverses symlinks on Windows.
-
This hybrid approach is necessary because:
-
Maven 4’s Module Source Hierarchy is designed for single-version module builds
-
The example’s educational value depends on demonstrating module version resolution in layers
-
Manual compilation of the second version preserves the example’s behavior while leveraging Maven 4 for the primary build