Switching Java versions
See also the updated article Switching Java Versions (Update).
Sometimes you’ll need to support more than one java version at a time. Especially if you use the JDK, you might want to use the specific java version in order to avoid to use accidently a new java API, that is later on not available at the runtime version.
Problem
Assume, you are using the
maven compiler plugin
with setting a source
and a target
option. Please consider the note, that I quoted from there:
Note: 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.
Let’s consider a very simple example. Java 8 introduced the java.time
API,
that is not available in Java 6.
The following sample program makes use of this API:
import java.time.OffsetDateTime;
public class JavaTime {
public static void main(String[] args) {
System.out.println(OffsetDateTime.now());
}
}
You can compile it with a Java 8 compiler for Java 6:
~$ javac -source 1.6 -target 1.6 JavaTime.java
warning: [options] bootstrap class path not set in conjunction with -source 1.6
1 warning
You silently ignore the warning - however, this is exactly the problem, we will see, when we run the program in different Java versions. With Java 8, everything is fine:
~$ java JavaTime
2015-09-25T10:48:58.458+02:00
However, with Java 6, you’ll get a NoClassDefFoundError
as Java 6 doesn’t know about any java.time.*
classes:
~$ java JavaTime
Exception in thread "main" java.lang.NoClassDefFoundError: java/time/OffsetDateTime
at JavaTime.main(JavaTime.java:6)
Caused by: java.lang.ClassNotFoundException: java.time.OffsetDateTime
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
... 1 more
So, while the compile bytecode is compatible with Java 6, it still doesn’t run under Java 6, as an API has been used that is not available in Java 6.
Solution
That’s one reason why you might want to switch between java version easily. I’ve created a couple of bash aliases
in my ~/.bashrc
file as follows:
alias java6="export JAVA_HOME=$HOME/programs/java6; export PATH=\"\$JAVA_HOME/bin:\${PATH/\$HOME\/programs\/java?\/bin:/}\""
alias java7="export JAVA_HOME=$HOME/programs/java7; export PATH=\"\$JAVA_HOME/bin:\${PATH/\$HOME\/programs\/java?\/bin:/}\""
alias java8="export JAVA_HOME=$HOME/programs/java8; export PATH=\"\$JAVA_HOME/bin:\${PATH/\$HOME\/programs\/java?\/bin:/}\""
It assumes, that you have installed your different java versions under $HOME/programs/java{6,7,8}
. I usually
extract the java archives under $HOME/programs/
and set a symlink to the specific version:
~$ cd $HOME/programs
~/programs$ ls -l java*
lrwxrwxrwx 1 andreas andreas 11 Mär 7 2015 java6 -> jdk1.6.0_45
lrwxrwxrwx 1 andreas andreas 11 Sep 25 11:23 java7 -> jdk1.7.0_80
lrwxrwxrwx 1 andreas andreas 11 Sep 25 11:18 java8 -> jdk1.8.0_60
lrwxrwxrwx 1 andreas andreas 8 Aug 31 2014 java9 -> jdk1.9.0
Now, if you have the aliases available, you can easily switch between java versions without polluting your PATH
environment variable:
~$java6
~$java -version
java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode)
~$java7
~$java -version
java version "1.7.0_80"
Java(TM) SE Runtime Environment (build 1.7.0_80-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)
~$java8
~$java -version
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
~$echo $PATH
/home/andreas/programs/java8/bin:/home/andreas/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
~$echo $JAVA_HOME
/home/andreas/programs/java8
As you can see in the end, the PATH
variable only contains the java8 version. By the way, $JAVA_HOME
is also
set accordingly.
Comments
No comments yet.Leave a comment
Your email address will not be published. Required fields are marked *. All comments are held for moderation to avoid spam and abuse.