Hi everyone, I am having issues with configuring build.gradle
for using Java 9+ modules.
Short description of my problem
I have been following the tutorial in the official documentation.
However, I ran into an issue: some extraneous arguments get passed to the application’s command line. This is due to the fact that gradle appends JVM args after the --module <module_name>
arg, and in Java 9+, all args after the --module <module_name>
arg get passed to the application itself, instead of to the underlying JVM. This issue has to do with roughly step 3 onward in the linked tutorial.
Steps to reproduce
1 - Clone the repo corresponding to the above tutorial above.
2 - cd into src/0-original
, src/1-single-module/
, or src/2-all-modules
, and execute ./gradlew :fairy:run
. Observe how in every case the JVM arguments look something like this for the executed application (a newline was inserted between each argument to improve readability):
/usr/lib/jvm/java-11-openjdk-amd64/bin/java
-Dfile.encoding=UTF-8
-Duser.country=US
-Duser.language=en
-Duser.variant
-cp
/home/user/building-java-9-modules-master/src/2-all-modules/fairy/build/classes/java/main:/home/user/building-java-9-modules-master/src/2-all-modules/fairy/build/resources/main:/home/user/building-java-9-modules-master/src/2-all-modules/pigs/build/libs/pigs.jar:/home/user/building-java-9-modules-master/src/2-all-modules/bears/build/libs/bears.jar:/home/user/building-java-9-modules-master/src/2-all-modules/formula/build/libs/formula.jar:/home/user/building-java-9-modules-master/src/2-all-modules/tale/build/libs/tale.jar:/home/user/building-java-9-modules-master/src/2-all-modules/actors/build/libs/actors.jar:/home/user/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/22.0/3564ef3803de51fb0530a8377ec6100b33b0d073/guava-22.0.jar:/home/user/.gradle/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/1.3.9/40719ea6961c0cb6afaeb6a921eaa1f6afd4cfdf/jsr305-1.3.9.jar:/home/user/.gradle/caches/modules-2/files-2.1/com.google.errorprone/error_prone_annotations/2.0.18/5f65affce1684999e2f4024983835efc3504012e/error_prone_annotations-2.0.18.jar:/home/user/.gradle/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.1/ed28ded51a8b1c6b112568def5f4b455e6809019/j2objc-annotations-1.1.jar:/home/user/.gradle/caches/modules-2/files-2.1/org.codehaus.mojo/animal-sniffer-annotations/1.14/775b7e22fb10026eed3f86e8dc556dfafe35f2d5/animal-sniffer-annotations-1.14.jar
org.gradle.fairy.app.StoryTeller
Notice how:
- Gradle passes a bunch of
-D
parameters to the JVM - Then comes the classpath
- Finally, the main class to execute
3 - cd
into src/3-application
, and execute ./gradlew :fairy:run
. In this case, gradle appends the --module-path
and --module
args before anything else, resulting in a command-line for the executed application similar to the following:
--module-path
/home/user/building-java-9-modules-master/src/3-application/fairy/build/classes/java/main:/home/user/building-java-9-modules-master/src/3-application/fairy/build/resources/main:/home/user/building-java-9-modules-master/src/3-application/pigs/build/libs/pigs.jar:/home/user/building-java-9-modules-master/src/3-application/bears/build/libs/bears.jar:/home/user/building-java-9-modules-master/src/3-application/formula/build/libs/formula.jar:/home/user/building-java-9-modules-master/src/3-application/tale/build/libs/tale.jar:/home/user/building-java-9-modules-master/src/3-application/actors/build/libs/actors.jar:/home/user/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/22.0/3564ef3803de51fb0530a8377ec6100b33b0d073/guava-22.0.jar:/home/user/.gradle/caches/modules-2/files-2.1/com.google.code.findbugs/jsr305/1.3.9/40719ea6961c0cb6afaeb6a921eaa1f6afd4cfdf/jsr305-1.3.9.jar:/home/user/.gradle/caches/modules-2/files-2.1/com.google.errorprone/error_prone_annotations/2.0.18/5f65affce1684999e2f4024983835efc3504012e/error_prone_annotations-2.0.18.jar:/home/user/.gradle/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.1/ed28ded51a8b1c6b112568def5f4b455e6809019/j2objc-annotations-1.1.jar:/home/user/.gradle/caches/modules-2/files-2.1/org.codehaus.mojo/animal-sniffer-annotations/1.14/775b7e22fb10026eed3f86e8dc556dfafe35f2d5/animal-sniffer-annotations-1.14.jar
--module
org.gradle.fairy.app/org.gradle.fairy.app.StoryTeller
-Dfile.encoding=UTF-8
-Duser.country=US
-Duser.language=en
-Duser.variant
org.gradle.fairy.app/org.gradle.fairy.app.StoryTeller
Notice how:
1 - All of the -D
parameters plus the repeated $MODULENAME/$MAINCLASSNAME are appended after the --module-path
and --module
args.
2 - Thus, they will get passed to the application’s command-line and not the JVM.
4 - In the main application code, i.e. src/3-application/fairy/src/main/java/org/gradle/fairy/app/StoryTeller.java
, do a simple System.out.println("ARGS: " + Arrays.toString(args));
to confirm the presence of extraneous arguments that were intended for the JVM and not for the application.
Note: to see the args passed to the JVM, I used doLast{println allJvmArgs}
inside the run
block of the build.gradle
file and also via cat /proc/$PID/cmdline
; both yielded the same results.
Impact of this issue
Running a modular application via the gradle run
task with this configuration will pass arbitrary arguments to the running application depending on the system properties (I think that is what the -D
parameters are, please correct me if I am wrong).
This leads to unexpected or broken behavior in the general case, since it might interfere with command-line processing for the application at hand. For example, what if the application depends on flags starting with -D
for its business logic?
This is obviously undesirable, and does not happen when using the classpath versions.
What should happen instead
Gradle should append the --module-path
and --module
args at the end, but I don’t know how to do that.
Is there a workaround or a different configuration that I can use to avoid this? i.e Is there really no way at this time to have gradle append the --module-path
, --module
, etc args only at the very end of the JVM command-line generated for the run
task?
If not, feel free to move this post to the Bugs section.
Note - affected plugins
By the way, this problem is also present when using plugins such as:
org.javamodularity.moduleplugin
org.openjfx.javafxplugin
The plugin authors would also benefit from a workaround for this problem, if such a workaround is possible in current versions of gradle.