Example example_addReads_addExports_reflection
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?
Module Dependency Graph, created with DepVis
Example shows …
-
addReads via reflection
modmain/Main adds a read relationship to modb dynamically via reflection
-
addExports via reflection
modb/pkgbinternal is also exported to modmain via reflection. For that, modmain/Main asks the (exported!) pkgb.BHelper to do this addExports. Adding cannot be done in modmain/Main directly, as the reflection method is caller-sensitive!
Note that for successful compilation, modmain/Main needs access to the exported BHelper. Therefore the option --add-exports is needed. Same thing during runtime.
|
Don’t try this at home
This example demonstrates an anti-pattern.
Using These flags should only be used for testing scenarios where you need test-only dependencies (like JUnit) without polluting production module descriptors. For a realistic example of proper usage, see Issue #5: Realistic testing example. Better alternatives: Declare proper See also: Why you shouldn’t use --add-exports. |
Output
This example uses golden master testing to ensure output consistency.
The expected output is compared with actual output using verify.sh.
Expected Output
Main: add reads of modmain to modb
BExportHelper: add exports of pkgbinternal to modmain
Main: pkgmain.Main, id=ID_Main_34, InternalB: from InternalB
Maven 4 Migration
This example demonstrates module system boundary overrides using both compile-time flags and runtime reflection APIs.
Maven 4 Compiler Changes
The Challenge
This example combines static module system overrides (compile-time) with dynamic overrides (runtime reflection).
At compile time, modmain needs access to modb, but without explicit requires declarations, the compiler will reject the code.
At runtime, the example uses reflection APIs to dynamically add additional module reads and exports, demonstrating programmatic module boundary manipulation.
The Solution
Configure compile-time access using compiler arguments:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>4.0.0-beta-3</version>
<configuration>
<compilerArgs>
<!-- Required for compile-time access from modmain to modb -->
<arg>--add-reads</arg>
<arg>modmain=modb</arg>
<arg>--add-exports</arg>
<arg>modb/pkgb=modmain</arg>
</compilerArgs>
</configuration>
</plugin>
The runtime configuration provides partial access via command-line flags:
java --module-path mlib \
--add-modules modb \
--add-exports modb/pkgb=modmain \
--module modmain/pkgmain.Main
Additional access is granted at runtime through reflection APIs in the code itself, as demonstrated in Main.java.
Key Takeaways
-
Compile-time flags establish basic module access for code compilation
-
Runtime flags can be split between command-line arguments and reflection APIs
-
Reflection APIs (
Module.addReads(),Module.addExports()) enable dynamic module boundary changes -
This hybrid approach is useful when module access needs vary based on runtime conditions
-
The example demonstrates that not all access needs to be configured via command-line flags