From the javac documentation:
--release
release
Compiles against the public, supported and documented API for a specific VM version. Supported release
targets are 6
, 7
, 8
, and 9
.
I read this as meaning that the compiler will treat any public methods and classes introduced in later versions like they don’t exist. For example, if code compiled with --release 8
imports or references java.lang.Module, the compiler will emit an error saying that that class doesn’t exist.
I do not see any part of that Gradle documentation stating that --release
is the preferred or official way to target a Java 8 JVM. I only see examples that use --release
as an example of how to add custom compiler options.
What it comes down to is, if you want compile for Java 8, you will need to exclude module-info.java.
If you want a single .jar that can both act as a module, and also be treated like a regular .jar by Java 8, you probably want a multi-release jar.
A multi-release jar is a concept introduced with Java 9. If you ignore all META-INF entries in the .jar other than the manifest, it looks exactly like a pre-9 .jar. No module-info, no Java 9+ class files.
All the Java 9 versions exist under META-INF/versions/9
in the .jar file. For instance, some entries in the .jar file might be:
META-INF/versions/9/module-info.class
META-INF/versions/9/com/example/myapp/MyApplication.class
And to signal to Java 9+ runtimes that the .jar is a multi-release .jar, you add this one manifest entry to the .jar:
Multi-Release: true
As for how to do all of this in Gradle, this blog recommends creating source sets. I don’t build with Gradle, so it’s not entirely clear to me from the documentation how to do it. Judging from the number of upvotes and the number of answers at How to make Multi-Release JAR Files with Gradle?, it appears other people aren’t clear on it either.