Description
Context
Maven projects which want to compile against Java < 9, but also want to prodive a JPMS module descriptor might choose to realize this using separate Maven Compiler Plugin executions, one compiling the main source code and another one only compiling the module-info.java
file.
A setup for this is described in the documentation for the Apache Maven Compiler Plugin, but that implementation is in my opinion flawed (will submit a Maven issue for this once their bug tracker is available again). It compiles all the code, including module-info.java
, against Java 9 and then compiles everything except module-info.java
against a lower Java version, hoping that this replaces all class files except module-info.class
. The issues here are:
- It relies on Java 9 creating the same class files as the lower version; however if Java 9 created additional synthetic classes or chose different synthetic class names (e.g. for anonymous classes), then those would remain in the created JAR.
- The created JAR contains directly in the root directory the
module-info.class
. This causes issues for some build tools (mostly for Android?) which cannot handle the file (see related issue in Gson).
For these reasons the compilation for module-info.java
should run with:
<release>9</release>
<includes>
<include>module-info.java</include>
</includes>
<multiReleaseOutput>true</multiReleaseOutput>
(Additionally the JAR plugin needs to be configured to set Mutli-Release: true
in the manifest.)
This only compiles the module-info.java
and places it under META-INF/versions/9
, where most build tools don't process classes (for Android, plugins have been updated to ignore these directories).
Issue
The issue with m2e and the recently integrated #253 is that the improved setup described above would cause m2e to detect Java 9 as highest release
, and then only consider its sources; that means the whole project would only have the module-info.java
file as source, and all the other source files compiled with an older version would be missing.
Potential solution
Would it make sense to remove the version requirement introduced by #253, and instead of overwriting the list of previously detected source files here, merge them instead?
Normally compiling with a newer Java version should not be a problem, and it only affects the IDE anyways. When you build with Maven from the command line it will choose the correct Java versions.
In my opinion having all files as source files available in the IDE weighs higher than compiling in the IDE with the exact Java version specified in the POM.
What do you think?
Open questions:
- When users have specified multiple executions to compile version specific classes to Multi Release folders (e.g. one verison of
MyClass
for Java 8 and one for Java 9), then the question is how Eclipse handles this case when both classes exist on the source path, with the same package name.
Workaround
For this specific use case of adding a module descriptor to a Java < 9 project, ModiTect seems to be well suited. It can compile an existing module-info.java
file, place it in the version specific META-INF/versions
folder of the JAR and set the Mutli-Release: true
attribute in the manifest.
This way you don't need two separate maven-compiler-plugin executions anymore and therefore no issues for m2e arise.