Older projects with module-info
Projects that want to be compatible with older versions of Java (i.e 1.8 or below bytecode and API), but also want to provide a module-info.java
for use on Java 9+ runtime, must be aware that they need to call javac
twice:
- the
module-info.java
must be compiled withrelease=9
, - while the rest of the sources must be compiled with the lower expected compatibility version of
source
/target
.
The preferred way to do this is by having 2 execution blocks, as described below:
- default
default-compile
execution withrelease=9
, - additional custom
base-compile
execution with expected target compatibility.
Notice that, in addition, JDK 9 only supports compilations for Java 6 and above, so projects wanting to be compatible with Java 5 or below need to use two different JDKs for the 2 executions. With toolchains configuration, it is quite easy to achieve this, even if a little bit more complex.
Java 6 to 8 Compatibility
In case you want the project to be Java 6, 7 or 8 compatible, you can simply use JDK 9 for both execution blocks.
The easiest way is to use Java 9 as the runtime for Maven, by setting JAVA_HOME=/path/to/jdk-9
before running mvn
. But if you want to use an older Java runtime for Maven, you can use the maven-toolchain-plugin to specify the shared JDK or a custom jdkToolchain and refer to the JDK 9 installation on your system.
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<release>9</release>
<!-- no excludes: compile everything to ensure module-info contains right entries -->
</configuration>
</execution>
<execution>
<id>base-compile</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<!-- recompile everything for target VM except the module-info.java -->
<excludes>
<exclude>module-info.java</exclude>
</excludes>
</configuration>
</execution>
</executions>
<!-- defaults for compile and testCompile -->
<configuration>
<release>6</release><!-- or 7 or 8 depending on compatibility expectations -->
<!-- Only required when Maven runtime JAVA_HOME isn't at least Java 9 and when haven't configured the maven-toolchains-plugin -->
<jdkToolchain>
<version>9</version>
</jdkToolchain>
</configuration>
</plugin>
</plugins>
[...]
</build>
[...]
</project>
Java 5 or below Compatibility
Given that Maven 3 requires newer Java release at runtime, you'll absolutely need to use Toolchains to use a JDK different from Maven runtime.
You could add a jdkToolchain to do base-compile execution-block as well referring to JDK 5.
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<release>9</release>
<!-- no excludes: compile everything to ensure module-info contains right entries -->
<!-- toolchain required when JAVA_HOME is JDK 8 or below -->
<jdkToolchain>
<version>9</version>
</jdkToolchain>
</configuration>
</execution>
<execution>
<id>base-compile</id>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<!-- recompile everything for target VM except the module-info.java -->
<excludes>
<exclude>module-info.java</exclude>
</excludes>
</configuration>
</execution>
</executions>
<!-- defaults for compile and testCompile -->
<configuration>
<source>1.5</source>
<target>1.5</target>
<!-- jdkToolchain required when JAVA_HOME is JDK 9 or above -->
<jdkToolchain>
<version>[1.5,9)</version>
</jdkToolchain>
</configuration>
</plugin>
</plugins>
[...]
</build>
[...]
</project>