Search code examples
javamavenmaven-compiler-plugin

maven-compiler-plugin enforce source compatibility with older JDK but compile in newer version


I am trying to keep my java project compatible with java 17 but actually compile and ships the jars with Java 21 compatibility level.

The rationale being that I am releasing a new major version and I would like to have Java 21 for baseline, but it might be a problem for some users. So the idea is to ship in Java 21 but keep the sources compatible with 17 in order to be able to bring back Java 17 build in a minor release if a user cannot upgrade with a valid reason. If all the users can migrate to Java 21 without issue, I will be able to use Java 21 only features without having to wait for a new major version of my software.

I am puzzled when configuring maven-compiler-plugin.

To ensure compatibility, the plan is:

  • Have jdk 21 installed
  • have the following configuration maven-compiler-plugin:
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <source>  17  </source>
    <target>  21  </target>
    <release> 17  </release>
  </configuration>
</plugin>

However, after reading What is the --release flag in the Java 9 compiler?, I am wondering if there will be a conflict between the release flag and the others.

  • I also intend to actually build and run in nightly CI runs on JDK 17, with only a JDK 17 installed:
<profile>
  <id>test-nightly</id>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>  17  </source>
          <target>  17  </target>
          <release> 17  </release>
        </configuration>
      </plugin>
    </plugins>
  </build>
</profile>

Am I configuring the maven-compiler-plugin correctly ?

Thanks in advance


Solution

  • After some investigation, it is not possible to do via the java build flags. The javac documentation says:

    Note: This can only be used when compiling for releases prior to JDK 9.
    As applicable, see the descriptions in [--release](https://docs.oracle.com/en/java/javase/21/docs/specs/man/javac.html#option-release), [-source](https://docs.oracle.com/en/java/javase/21/docs/specs/man/javac.html#option-source), or [-target](https://docs.oracle.com/en/java/javase/21/docs/specs/man/javac.html#option-target) for details.
    
    --release release
    
        Compiles source code according to the rules of the Java programming language for the specified Java SE release, generating class files which target that release. Source code is compiled against the combined Java SE and JDK API for the specified release.
    
        The supported values of release are the current Java SE release and a limited number of previous releases, detailed in the command-line help.
    
        For the current release, the Java SE API consists of the java.*, javax.*, and org.* packages that are exported by the Java SE modules in the release; the JDK API consists of the com.* and jdk.* packages that are exported by the JDK modules in the release, plus the javax.* packages that are exported by standard, but non-Java SE, modules in the release.
    
        For previous releases, the Java SE API and the JDK API are as defined in that release.
    
        Note: When using --release, you cannot also use the [--source](https://docs.oracle.com/en/java/javase/21/docs/specs/man/javac.html#option-source)/-source or [--target](https://docs.oracle.com/en/java/javase/21/docs/specs/man/javac.html#option-target)/-target options.
    
        Note: When using --release to specify a release that supports the Java Platform Module System, the --add-exports option cannot be used to enlarge the set of packages exported by the Java SE, JDK, and standard modules in the specified release
    

    And especially the line Note: When using --release, you cannot also use the --source/-source or --target/-target options.

    The solution I went for is based on:

    • configuring the poms to 17 via the release flag
    • rewriting the poms in the CI/CD thanks to the following command before releasing
    mvn versions:set-property -Dproperty=maven.compiler.release -DnewVersion=21