question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Feature request: Separate compilation of module-info.java

See original GitHub issue

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:

  1. Low-level API: separate compilation of module-info.java.
  2. High-level API: easy setting of javac --release option, separately for main Java code and for module-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:

  • 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.:

  • Maven:
  • Ant:
    • Lombok (JDK 9 module-info.class in root dir)

There are also some libraries that:

Vavr /ˈveɪ.vɚ/

Let’s have a closer look at vavr’s case:

  1. It’s a quite popular library (3000+ Github stars) targeting JDK 8.
  2. Its creator, @danieldietrich, is (or was?) a believer in JPMS.
  3. However, as https://github.com/vavr-io/vavr/issues/2230#issuecomment-374792372 shows, he backed out of it (partly because the required Gradle configuration was too complex).
  4. I personally think it’s a shame if such a popular library cannot be easily shipped with a module-info.class while still targeting JDK 8.

Proposed DSL

Note: Everything in this section (especially naming) is TBD.

Low-level API

Extra property on moduleOptions extension:

build.gradle
compileJava.moduleOptions.compileModuleInfoSeparately = true
build.gradle.kts
tasks {
  compileJava.moduleOptions.compileModuleInfoSeparately = true
}

High-level API

Special modularity extension with two functions:

  • for releasing to JDK 6-8:
    • 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:

  1. in the root output directory (natural; corresponds to module-info.java location)
  2. 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, @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’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?

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.class from a special notation (there’s even no module-info.java there edit: 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)

Related StackOverflow questions

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:14

github_iconTop GitHub Comments

1reaction
paulbakkercommented, Apr 4, 2019

Merged the work done by @tlinkowski! Will be in the next release (which I plan to publish today)

1reaction
paulbakkercommented, Mar 22, 2019

@tlinkowski This is great! Thanks for the detailed writeup and PR. I’m fully onboard with supporting this, seems like a great feature to further increase JPMS adoption. I’ll need a few days before I can give it the attention it deserves (trip coming up this weekend), but I’ll get to it as soon as possible.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Building Modular Java Applications with Gradle - Alex Kudlick
You'll end up cobbling together some knowledge of how modules work from various different sources, experimenting with command line compilation ...
Read more >
21. Java Module System - Java Pocket Guide, 4th Edition [Book]
The Java Platform Module System (JPMS) is implemented as a separate layer ... up of a JSR (Java Specification Request) and multiple JEPs...
Read more >
Java Modules - Jenkov.com
A Java module is a packaging mechanism that enables you to package a Java application or Java API as a separate Java module....
Read more >
A Guide to Java 9 Modularity - Baeldung
They are named and defined in the compiled module-info.class file included in the assembled JAR. Automatic Modules – We can include ...
Read more >
Understanding Java 9 Modules - Oracle
Goals · Reliable configuration—Modularity provides mechanisms for explicitly declaring dependencies between modules in a manner that's recognized both at compile ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found