An example Gradle project that uses the Java Platform Module System (JPMS).
There are a few things to highlight about this project vs. a non-JPMS project:
- The
module-info.java
files - Configuring the Gradle Application Plugin to work with modules with
mainModule.set("dgroomes.runner")
- When you build a distribution with
./gradlew install
, the shell/start script that is generated (build/install/runner/bin/runner
) by the Gradle Application Plugin defines aMODULE_PATH
variable in addition to theCLASSPATH
variable that normally exists.
Tip: disassemble a module-info.class
file to view its content using javap
. For example: javap --module-path . module-info.class
.
I've found this to be helpful while learning about JPMS.
Follow these instructions to build and run the demo program:
- Pre-requisite: Java 21
- Build and run the program:
-
./gradlew run
- It should print something that looks like the following.
-
> Task :runner:run [main] INFO dgroomes.java_modules.runner.Main - You say: hello! [main] INFO dgroomes.java_modules.runner.Main - You heard: hello!, hello!, hello! ... [main] INFO dgroomes.java_modules.runner.Main - You say: { "message": "hello from JSON!" } [main] INFO dgroomes.java_modules.runner.Main - You heard: hello from JSON!, hello from JSON!, hello from JSON! ...
-
General clean-ups, TODOs and things I wish to implement for this project:
- DONE Incorporate Jackson as a dependency to this project because apparently Jackson has some integrations with JPMS. It would be useful to show how to incorporate a Gradle dependency that publishes module info. How does that work?
- DONE (added slf4j 1.7.x. The 1.8.x and 2.x branches are modularized but are beta) Incorporate a non-modularized dependency to this project. This is an almost universal use-case because so many libraries are not modularized. This requires declaring an "automatic module".
- OBSOLETE (slf4j 2.x is general availability for a while now and is modularized) Patch the slf4j dependency to be modular (will this let me
jlink
it without needingjdeps
?). For reference about how to do this, see:- StackOverflow Q&A: How to inject module declaration into JAR? (note: this makes sense for one jar but I couldn't get it to work with multiple jars that have dependency relationships between them, like slf4j)
- Gradle docs: Building Java Modules with Legacy Libraries Sample (note: this is the ticket!)
- DONE Gradle's module support was promoted in Gradle 7.x. Read the release notes.
In particular, the
inferModulePath
call is no longer required. Delete it. - DONE Showcase JPMS's strength when it comes to strongly encapsulating implementation details. For example, can I have classes that are used as implementation details in a package (or maybe sub-package?) and then export just a particular "ordained" package?