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>
- -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
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 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 -target option. So although the compiler should consider it, that's not the case.
Let's understand this in more detail. 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, though we provided the –source and —target options as 8, the compilation was performed against the Java 9 classes.
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 we have no 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.8.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.8.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.