mavenmaven-compiler-plugin

"maven.compiler.release" as a replacement for source and target?


I have two questions about maven.compiler.release-tag

I want to replace

<properties>
    <maven.compiler.source>12</maven.compiler.source>
    <maven.compiler.target>12</maven.compiler.target>
</properties>

to

<properties>
     <maven.compiler.release>12</maven.compiler.release>
</properties>

If I use <maven.compiler.release>-property, do I have to set the release tag also in the plugin?

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.0</version>
    <configuration>
        <!-- do I need that ? -->
        <release>12</release>
    </configuration>
</plugin>

According to https://www.baeldung.com/maven-java-version, it is set to both.

If I use maven.compiler.release instead of maven.compiler.source and maven.compiler.target, then -bootclasspath is also set and will do a cross-compile. What does this mean? Will the compilation file sizes with set -bootclasspath be bigger or will the compilation need more time?


Solution

  • The "simple suggestion" in the other answer won't work correctly because unfortunately the situation is not simple. The compiler options mean slightly different things. The maven.compiler.source and maven.compiler.target options refer to the source code format and the format of the generated class files, respectively. But they do not take into account API changes as maven.compiler.release does.

    So if you blindly just use <maven.compiler.source>8</maven.compiler.source> and <maven.compiler.target>8</maven.compiler.target>, if you build using Java 11 for example the generated class files will support Java 8 but the API may still rely on Java 11 changes and break when run on Java 8. See How should javac 11 link methods overridden in later versions with a Java 8 target? for more discussion.

    The solution is not so simple if you want to designate Java 8 but build on Java 9+. You'll need to specify the source and target as you are doing, using compiler options supported by Java 8:

    <properties>
      <maven.compiler.source>8</maven.compiler.source>
      <maven.compiler.target>8</maven.compiler.target>
    </properties>
    

    Then you'll need to set up a separate profile in the <profiles> section that is only activated in Java 9+ to turn on the maven.compiler.release option:

    <profile>
      <id>java-8-api</id>
      <activation>
        <jdk>[9,)</jdk>
      </activation>
      <properties>
        <maven.compiler.release>8</maven.compiler.release>
      </properties>
    </profile>
    

    That way if you build on Java 9+, maven.compiler.release will come into effect and restrict the API to be compatible with Java 8. If you build on Java 8, the other two options will set the source code and class file format to Java 8, and the API will be Java 8 compatible by definition.

    The better option for everyone involved of course is just to move to Java 11 as soon as possible.