maven-compiler-plugin icon indicating copy to clipboard operation
maven-compiler-plugin copied to clipboard

There are difference between `maven.compiler.release` and `maven.compiler.target` during compiling projects which use ```sun.misc.Unsafe``` with JDK17+

Open zrlw opened this issue 1 month ago • 4 comments

Affected version

3.14.0, 3.14.1

Bug description

There are import sun.misc.Unsafe; in our codes, we want the target class bytecode version is java 8 for the sake of compatibility.

During runing mvn compile with jdk17+,

  1. we will encounter Cannot compile: java: package sun.misc does not exist ERROR and the compilation process will be terminated with failure if we set maven.compiler.release to 8
  <properties>
    <maven.compiler.release>8</maven.compiler.release>
  </properties>

or configure release of maven-compiler-plugin to 8 at the pom.xml like this,

    <profile>
      <id>jdk9-compile</id>
      <activation>
        <jdk>[1.9,)</jdk>
      </activation>
      <build>
        <plugins>
          <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
              <release>8</release>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </profile>
  1. Unsafe is internal proprietary API and may be removed in a future release Warning will appear and the compilation process will continue if we set maven.compiler.target to 1.8 at the pom.xml (delete jdk9-compile profile configuration) like this,
  <properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

zrlw avatar Nov 06 '25 05:11 zrlw

Hi @zrlw - could you confirm you understand there are two options --target and --release for javac that serve different purpose and act differently?

pzygielo avatar Nov 06 '25 09:11 pzygielo

Hi @zrlw - could you confirm you understand there are two options --target and --release for javac that serve different purpose and act differently?

  1. https://github.com/apache/maven-compiler-plugin/blob/master/src/site/markdown/examples/set-compiler-release.md?plain=1#L20

Starting with JDK 9, the javac executable can accept the --release option to specify against which Java SE release you want to build the project. For example, you have JDK 17 installed and used by Maven, but you want to build the project against Java 11. The --release option ensures that the code is compiled following the rules of the programming language of the specified release, and that generated classes target the release as well as the public API of that release. This means that, unlike the old --source and --target options, the compiler will detect and generate an error when using APIs that don't exist in previous releases of Java SE.

  1. https://docs.oracle.com/en/java/javase/25/docs/specs/man/javac.html#option-target

--target release or -target release Generates class files suitable for the specified Java SE 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. Note: The target release must be equal to or higher than the source release. (See [--source

  1. https://docs.oracle.com/en/java/javase/25/docs/specs/man/javac.html#option-release

--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/-source or --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.

zrlw avatar Nov 06 '25 09:11 zrlw

https://maven.apache.org/plugins/maven-compiler-plugin/examples/set-compiler-source-and-target.html

Merely setting the target option does not guarantee that your code actually runs on a JRE with the specified version. The pitfall is unintended usage of APIs that only exist in later JREs which would make your code fail at runtime with a linkage error. To avoid this issue, you can either configure the compiler's boot classpath to match the target JRE, or use the Animal Sniffer Maven Plugin to verify your code doesn't use unintended APIs, or better yet use the release option supported since JDK 9. Since plugin version 3.13.0 you can use the release property also on JDK 8. The compiler plugin will convert it to source and target automatically.

zrlw avatar Nov 06 '25 09:11 zrlw

 unlike the old --source and --target options,
the compiler will detect and generate an error when using APIs that don't exist in previous releases of Java SE.

it seemed that sun.misc.Unsafe will be considered as not-existed API if set maven.compiler.release instead of maven.compiler.target no matter the release version is 8 or not.

zrlw avatar Nov 06 '25 09:11 zrlw