Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this tutorial, we’ll learn about Java 9’s new command-line option –release. The Java compiler running with the –release N option automatically generates class files compatible with Java version N. We’ll discuss how this option relates to the existing compiler command-line options -source and -target.

2. Need for —release Option

To understand the need for a —release option, let us consider a scenario where we need to compile our code with Java 8 and want the compiled classes to be compatible with Java 7.

It was possible to achieve this before Java 9 by using the —source and —target options, where

  • -source: specifies the Java version accepted by the compiler
  • -target: specifies the Java version of the class files to produce

Suppose the compiled program uses APIs exclusively available in the current version of the platform, in our case, Java 8. In that case, the compiled program cannot run on earlier versions like Java 7, regardless of the values passed to the –source and –target options.

Furthermore, we would need to add the –bootclasspath option along with –source and –target to work in Java versions 8 and below.

To streamline this cross-compilation problem, Java 9 introduced the new option —release to simplify the process.

3. Relationship With -source and -target Options

According to the JDK definition, –release N can be expand as:

  • for N < 9, -source N -target N -bootclasspath <documented-APIs-from-N>
  • for N >= 9, -source N -target N –system <documented-APIs-from-N>
Here are a few details about these internal options:
  • -bootclasspath: a semicolon-separated list of directories, JAR archives, and ZIP archives for searching boot class files
  • system: overrides the location of system modules for Java 9 and later versions
Also, the documented APIs are located in $JDK_ROOT/lib/ct.sym, which is a ZIP file containing class files stripped down according to the Java version.

For Java version N< 9, these APIs include the bootstrap classes retrieved from jars located in jre/lib/rt.jar and other related jars.

For Java version N >= 9, these APIs include the bootstrap classes retrieved from the Java modules located in the jdkpath/jmods/ directory.

4. Usage with the Command Line

First, let’s create a sample class and use the overridden flip method of ByteBuffer, which was added in Java 9:

import java.nio.ByteBuffer;

public class TestForRelease {

    public static void main(String[] args) {
        ByteBuffer bb = ByteBuffer.allocate(16);
        bb.flip();
        System.out.println("Baeldung: --release option test is successful");
    }
}

4.1. With Existing -source and -target Option

Let’s compile the code in Java 9 using the -source and -target options value as 8:

/jdk9path/bin/javac TestForRelease.java -source 8 -target 8 

The result of this is successful, but with a warning:

warning: [options] bootstrap class path not set in conjunction with -source 8

1 warning

Now, let’s run our code on Java 8:

/jdk8path/bin/java TestForRelease

We see that this fails:

Exception in thread "main" java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer;
at com.corejava.TestForRelease.main(TestForRelease.java:9)

As we can see, this is not what we expected to see with the given value of 8 in our -release and -target option. So although the compiler should consider it, that’s not the case.

Let’s understand this in more detail.

In releases before Java 9, the Buffer class contained the flip method:

public Buffer flip() {
    ...
 }

In Java 9, ByteBuffer, which extends Buffer, overrides the flip method:

@Override
public ByteBuffer flip() {
    ...
}

When this new method is compiled on Java 9 and run on Java 8,  we get the error as both methods have different return types and method lookup using the descriptor fails at runtime:

Exception in thread "main" java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer;
at com.corejava.TestForRelease.main(TestForRelease.java:9)

 

During compilation, we got the warning which we ignored earlier. This is because the Java compiler, by default, compiles with the latest APIs. In other words, the compiler used Java 9 classes even though we specified –source and –target to be 8, so our program failed to run on Java 8.

Therefore, we must pass another command-line option called –bootclasspath to the Java compiler to choose the correct versions.

Now, let’s recompile the same code with –bootclasspath option:

/jdk9path/bin/javac TestForRelease.java -source 8 -target 8 -Xbootclasspath ${jdk8path}/jre/lib/rt.jar

Again, the result of this is successful, and this time we don’t have any warning.

Now, let’s run our code on Java 8, and we see that this is successful:

/jdk8path/bin/java TestForRelease 
Baeldung: --release option test is successful

Although cross-compilation works now, we had to provide three command-line options.

4.2. With –release Option

Now, let’s compile the same code with the –release option:

/jdk9path/bin/javac TestForRelease.java —-release 8

Again, the compilation is successful this time, with no warnings.

Finally, when we run the code on Java 8, we see that it is successful:

/jdk8path/bin/java TestForRelease
Baeldung: --release option test is successful

We see that it’s straightforward with the —release option as javac internally sets the correct values for -source, -target, and –bootclasspath.

5. Usage with the Maven Compiler Plugin

Usually, we use build tools like Maven or Gradle and not the command-line javac tool. So in this section, we will see how we can apply the –release option in the maven compiler plugin.

Let’s first see how we use the existing -source and -target options:

<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.12.1</version>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
 </plugins>

Here’s how we can use the –release option :

<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.12.1</version>
        <configuration>
            <release>1.8</release>
        </configuration>
    </plugin>
 </plugins>

Although the behavior is the same as we described earlier, the way we are passing these values to the Java compiler is different.

6. Conclusion

In this article, we learned about the –release option and its relationship with the existing -source and -target options. Then, we saw how to use the option on the command line and with the Maven compiler plugin.

Finally, we saw that the new —release option requires fewer input options for cross-compilation. For this reason, it is recommended to use it whenever possible instead of the -target, -source, and -bootclasspath options.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
2 Comments
Oldest
Newest
Inline Feedbacks
View all comments
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.