Example example_resolved-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?

Modules in this example

  • TODO

  • modmain has a Main class which is started in run.sh

Module Dependency Graph, created with DepVis

Example’s Module Dependency Graph

Example shows …​

TBD
Example for

* resolvedmods: What is loaded?

Modules moda, modb (requires moda), modc

The Main method in each module outputs the modules in the boot layer:

* moda/pkga.AMain: The boot layer contains java., jdk. and moda
* modb/pkgB.BMain: The boot layer contains java., jdk., moda, modb
* modc/pkgC.CMain: The boot layer contains java., jdk., modc
* modb/pkgb.BMain with --add-modules modc: The boot layer contains java., jdk., moda, modb, modc

Although only java.base is required, some java.* modules are loaded (java.rmi, java.scripting, java.logging, ...)

An automatic module is only loaded if it is also required.
First the configuration is created based on the required relationships, then the read edges for automatic modules are added.

See also "State of the Module System":

*After* a module graph is resolved, therefore, an automatic module
is made to read every other named module, whether automatic or explicit.

Output

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

Expected Output

Now we have these boot layer 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, moda]
Now we have these boot layer 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, moda, modb]
Now we have these boot layer 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, modc]
Now we have these boot layer 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, moda, modb, modc]
Now we have these boot layer 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, moda, modb]
Now we have these boot layer modules:
[java.base, moda, modb]
Now we have these boot layer modules:
[java.base, java.logging, moda, modb]
java.base file://<JAVA_HOME>/jmods/java.base.jmod
moda file://<PROJECT_ROOT>/mlib/moda.jar
modb file://<PROJECT_ROOT>/mlib/modb.jar

Providers:
  java.base provides java.nio.file.spi.FileSystemProvider used by java.base
Now we have these boot layer modules:
[java.base, moda, modb]

Actual Output

Now we have these boot layer 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, moda]
Now we have these boot layer 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, moda, modb]
Now we have these boot layer 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, modc]
Now we have these boot layer 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, moda, modb, modc]
Now we have these boot layer 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, moda, modb]
Now we have these boot layer modules:
[java.base, moda, modb]
Now we have these boot layer modules:
[java.base, java.logging, moda, modb]
java.base file://<JAVA_HOME>/jmods/java.base.jmod
moda file://<PROJECT_ROOT>/mlib/moda.jar
modb file://<PROJECT_ROOT>/mlib/modb.jar

Providers:
  java.base provides java.nio.file.spi.FileSystemProvider used by java.base
Now we have these boot layer modules:
[java.base, moda, modb]

Maven 4 Output

Now we have these boot layer 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, moda]
Now we have these boot layer 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, moda, modb]
Now we have these boot layer 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, modc]
Now we have these boot layer 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, moda, modb, modc]
Now we have these boot layer 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, moda, modb]
Now we have these boot layer modules:
[java.base, moda, modb]
Now we have these boot layer modules:
[java.base, java.logging, moda, modb]
java.base file://<JAVA_HOME>/jmods/java.base.jmod
moda file://<PROJECT_ROOT>/mlib/moda.jar
modb file://<PROJECT_ROOT>/mlib/modb.jar

Providers:
  java.base provides java.nio.file.spi.FileSystemProvider used by java.base
Now we have these boot layer modules:
[java.base, moda, modb]

Maven 4 Migration

This example has been migrated to Maven 4 using the standard Module Source Hierarchy approach.

Key Characteristics

Multiple Modules

This example compiles three modules (moda, modb, modc) demonstrating module resolution, not a single modmain module.

The pom.xml defines all three modules in the <sources> section.

Multi-Scenario Testing

The m4/run.sh script executes 8 different module resolution scenarios.

  1. Running with root module moda (standalone)

  2. Running with root module modb (requires moda)

  3. Running with root module modc (standalone)

  4. Running with root module modb plus --add-modules modc

  5. Running with root module modb plus automatic module javax.json (from ../amlib)

  6. Running with root module modb plus --limit-modules

  7. Running with root module modb plus --limit-modules on specific JDK modules

  8. Using jlink to create a custom runtime image with modb, then running from that image

jlink Integration

Scenario 8 demonstrates creating a custom runtime image using jlink.

  • Creates minimal runtime with only required modules

  • Demonstrates jlink --module-path with both application modules and JDK modules

  • Runs the application from the linked runtime image

Automatic Module Reference

The run script references ../amlib for the javax.json automatic module in scenario 5, demonstrating that automatic modules are only loaded when explicitly required or added.

Maven (4) uses maven-jar-plugin with classifiers, creating JARs with names like:

target/example_resolved-modules-m4-1.0-SNAPSHOT-moda.jar
target/example_resolved-modules-m4-1.0-SNAPSHOT-modb.jar
target/example_resolved-modules-m4-1.0-SNAPSHOT-modc.jar

However, when using jlink, it outputs the actual JAR filenames in its verbose output. The golden master test expects simple JAR names (e.g., moda.jar) for consistency with the original example.

To solve this, compile.sh copies the JARs to mlib/ with simple names:

# Copy JARs to mlib with simple names for jlink
for mod in moda modb modc; do
    cp "target/example_resolved-modules-m4-1.0-SNAPSHOT-${mod}.jar" "mlib/${mod}.jar"
done

The run.sh script then uses --module-path mlib instead of --module-path target, ensuring:

  • Simple JAR names in jlink output (matches golden master expectations)

  • Consistent module-path references throughout all 8 test scenarios

  • Compatibility with both direct Java execution and jlink-created runtime images

While --module-path target would work for direct Java execution, jlink would output the full classifier-based names, breaking golden master verification. The JAR copying approach maintains output consistency across all scenarios.