You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'd like to request a feature for library developers who need to target JDK 6-8 but who also want to provide a module-info.class (as per Option 3 by @jodastephen).
The proposed feature has two parts:
Low-level API: separate compilation of module-info.java.
High-level API: easy setting of javac --release option, separately for main Java code and for module-info.java.
Still, those maintainers could make the most of JPMS by:
providing module-info.class for consumers who put the library on module path,
compiling module-info.java against the remaining classes of this module and against other modules (which provides better encapsulation and prevents split packages).
So providing a module-info.class is like saying:
Hey, I'm JPMS-compatible! You can safely put me on the module path — I guarantee to have no split packages!
To sum up, I see this feature request as great means of promoting JPMS! Would you agree, @paulbakker, @sandermak?
Examples
Here are some popular libraries that provide module-info.class while targeting JDK 6-8, e.g.:
mixedJavaRelease(int mainJavaRelease, int moduleInfoJavaRelease = 9)
for releasing to JDK 9+
standardJavaRelease(int mainJavaRelease)
For example, the most common configuration (JDK 8 + JDK 9 module-info.class) would be a one-liner:
build.gradle
modularity.mixedJavaRelease 8
build.gradle.kts
modularity.mixedJavaRelease(8)
Proposed behavior
module-info.java location
I propose to leave module-info.java in src/main/java (I don't see any need to put it in a separate source set directory).
module-info.class location
There are two places where module-info.class can end up:
in the root output directory (natural; corresponds to module-info.java location)
in META-INF/versions/9 (Multi-Release JAR, AKA MRJAR)
Having read a post on MRJARs by @melix, I'm rather suspicious of MRJARs, and so I prefer option 1.
On the other hand, @gunnarmorlingclaims that it's better to use option 2 because module-info.class "will be out of the way in most cases when being used on an older Java version". But I don't really know why, because as far as I understand, any tool that scans the classpath (like Guava's ClassPath) will return module-info.class no matter where it is (based on its .class extension). @gunnarmorling, would you care to give me a pointer here?
However, ModiTect does much more than I request here: ModiTect actually generatesmodule-info.class from a special notation (there's even no module-info.java thereedit: it can actually parse module-info.java). Personally, I find it too complex for my needs.
Badass-Jar plugin
@siordache also created a Gradle plugin that lets one "seamlessly create modular jars that target a Java release before 9".
It looks quite nice, however:
I'm not sure how it plays along with org.javamodularity.moduleplugin (and I'd like to use it for patching modules, testing on module-path, etc.)
in order to build the proper JAR and make sure your module-info.java is correct, you actually have to run the build twice (./gradlew jar and ./gradlew -PjavaCompatibility=9 jar) - too complex
it doesn't use javac's --release option, which (as opposed to using -source and -target) guarantees that only the right APIs are referenced (e.g. it throws when compiling optional.isEmpty() with --release 8)
it produces only Multi-Release JARs, and I'm somewhat skeptical about them (as I mentioned before)
Overview
I'd like to request a feature for library developers who need to target JDK 6-8 but who also want to provide a
module-info.class(as per Option 3 by @jodastephen).The proposed feature has two parts:
module-info.java.--releaseoption, separately for main Java code and formodule-info.java.Justification
General
Library maintainers need to target JDK 6-8 because these JDKs (especially JDK 8) are still very popular (taking ~95% share in 2018, and predicted to take ~90% in 2019).
Still, those maintainers could make the most of JPMS by:
module-info.classfor consumers who put the library on module path,module-info.javaagainst the remaining classes of this module and against other modules (which provides better encapsulation and prevents split packages).So providing a
module-info.classis like saying:To sum up, I see this feature request as great means of promoting JPMS! Would you agree, @paulbakker, @sandermak?
Examples
Here are some popular libraries that provide
module-info.classwhile targeting JDK 6-8, e.g.:module-info.classin root dir)module-info.classin root dir)module-info.classinMETA-INF/versions/9- Multi-Release JAR)module-info.classin root dir)There are also some libraries that:
Vavr /ˈveɪ.vɚ/
Let's have a closer look at vavr's case:
module-info.classwhile still targeting JDK 8.Proposed DSL
Note: Everything in this section (especially naming) is TBD.
Low-level API
Extra property on
moduleOptionsextension:build.gradle
build.gradle.kts
tasks { compileJava.moduleOptions.compileModuleInfoSeparately = true }High-level API
Special
modularityextension with two functions:mixedJavaRelease(int mainJavaRelease, int moduleInfoJavaRelease = 9)standardJavaRelease(int mainJavaRelease)For example, the most common configuration (JDK 8 + JDK 9
module-info.class) would be a one-liner:build.gradle
modularity.mixedJavaRelease 8build.gradle.kts
modularity.mixedJavaRelease(8)Proposed behavior
module-info.javalocationI propose to leave
module-info.javainsrc/main/java(I don't see any need to put it in a separate source set directory).module-info.classlocationThere are two places where
module-info.classcan end up:module-info.javalocation)META-INF/versions/9(Multi-Release JAR, AKA MRJAR)Having read a post on MRJARs by @melix, I'm rather suspicious of MRJARs, and so I prefer option 1.
On the other hand, @gunnarmorling claims that it's better to use option 2 because
module-info.class"will be out of the way in most cases when being used on an older Java version". But I don't really know why, because as far as I understand, any tool that scans the classpath (like Guava'sClassPath) will returnmodule-info.classno matter where it is (based on its.classextension). @gunnarmorling, would you care to give me a pointer here?Alternatives
ModiTect
It's fair to mention ModiTect (by @gunnarmorling) and its Gradle plugin (by @siordache) here.
However, ModiTect does much more than I request here: ModiTect actually generates
module-info.classfrom a special notation (there's even noedit: it can actually parsemodule-info.javatheremodule-info.java). Personally, I find it too complex for my needs.Badass-Jar plugin
@siordache also created a Gradle plugin that lets one "seamlessly create modular jars that target a Java release before 9".
It looks quite nice, however:
I'm not sure how it plays along withorg.javamodularity.moduleplugin(and I'd like to use it for patching modules, testing on module-path, etc.)module-info.javais correct, you actually have to run the build twice (./gradlew jarand./gradlew -PjavaCompatibility=9 jar) - too complex--releaseoption, which (as opposed to using-sourceand-target) guarantees that only the right APIs are referenced (e.g. it throws when compilingoptional.isEmpty()with--release 8)it produces only Multi-Release JARs, and I'm somewhat skeptical about them (as I mentioned before)Related StackOverflow questions