Using multiple Java SDK versions on same machine
As a developer, we often work on more than one java based projects and having many open source projects on our local machine is not uncommon. Java 7 is still used by some frameworks, Java 8 has been there for long time and some projects are still migrating to Java 8. And now Java 9 is almost at the corner!
There can be situations where we have different projects that need different JDK’s. Everything depends on what JDK you have on classpath i.e. using
JAVA_HOME. How convenient is it, to keep changnig
JAVA_HOME every time you switch between projects.
If you are working in IDE, you may have some extensions in IDE that allows you to set JDK’s at project level. Almost all common IDEs like eclipse, IntelliJ, Netbeans etc. allow this. But how about terminal or system level?
JDK9 is almost ready to make prime time release. In previous post, we already saw how to Install JDK9 Early Access builds. When I installed JDK9, I realized, I now have Java 7,8 and 9 installed on my laptop. How am I gonna switch between versions? I don’t want to set JDK9 as default JDK as it might cause many other tools to fail.
Know your environment
What is current default java?
Check the current java version used by running
java -version on terminal.
▶ java -version java version "9" Java(TM) SE Runtime Environment (build 9+177) Java HotSpot(TM) 64-Bit Server VM (build 9+177, mixed mode)
What other Java versions are installed?
To check what all versions are installed, you can run
/usr/libexec/java_home -V on terminal. It will print all java version paths.
▶ /usr/libexec/java_home -V Matching Java Virtual Machines (5): 9, x86_64: "Java SE 9" /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home 1.8.0_131, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home 1.8.0_73, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0_73.jdk/Contents/Home 1.8.0_60, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home 1.7.0_79, x86_64: "Java SE 7" /Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home
The path printed at the last line is where default
/usr/bin/java is pointing to -
▶ /usr/bin/java -version java version "9" Java(TM) SE Runtime Environment (build 9+177) Java HotSpot(TM) 64-Bit Server VM (build 9+177, mixed mode)
The Solution: JEnv
This is what JEnv website says about it -
And it does what it says, helps you manage your java environment.
|As far as I know, this JEnv is different than JEnv.io.|
JEnv website has good installation details but here are quick steps for Mac OSX -
Install using Homebrew -
brew install jenv
echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.bash_profile $ echo 'eval "$(jenv init -)"' >> ~/.bash_profile
jenvon terminal to verify its installed.
Add Java Versions to JEnv
Now that we have JEnv installed, lets add our versions in JEnv so it can manage them. For every JDK path, run
jenv add <path> command on terminal. To add JDK 7, 8 and 9 to JEnv, I ran -
jenv add /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home jenv add /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home jenv add /Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home
Check what versions are available in JEnv now by running
jenv versions command. It should print the JDK version numbers (labels) that JEnv is now managing.
▶ jenv versions system 1.7 220.127.116.11 1.8 18.104.22.168 9 oracle64-22.214.171.124 * oracle64-126.96.36.199 (set by /Users/manik/.jenv/version) oracle64-9
At any time, you may run
jenv doctor, to verify your jenv installation and setup -
▶ jenv doctor [OK] JAVA_HOME variable probably set by jenv PROMPT [OK] Java binaries in path are jenv shims [OK] Jenv is correctly loaded
Manage Java Version
JEnv allows you to set Java versions at global, local or shell level.
Java version set as global will be applicable all over system and can be overwritten by local or shell. Below command sets 1.8 as global java version on system -
java global 1.8
To check what version is set as global, run
jenv global -
▶ jenv global oracle64-188.8.131.52
Local sets the Java version for a directory and all sub-directories.
Let’s create a folder java9 and set it to use JDK9. We will run
java -version before and after setting jdk 9, so we can see the versions.
~ ▶ mkdir java9 && cd java9 ~/java9 ▶ java -version java version "1.8.0_131" Java(TM) SE Runtime Environment (build 1.8.0_131-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode) ~/java9 ▶ jenv local 9 ~/java9 ▶ java -version java version "9" Java(TM) SE Runtime Environment (build 9+177) Java HotSpot(TM) 64-Bit Server VM (build 9+177, mixed mode) ~/java9 ▶ mkdir subfolder && cd subfolder ~/java9/subfolder ▶ java -version java version "9" Java(TM) SE Runtime Environment (build 9+177) Java HotSpot(TM) 64-Bit Server VM (build 9+177, mixed mode)
Shell sets the Java version for current instance of the shell. This will override any global as well as local version set earlier. It lives only until current shell is open.
Lets set the shell to use java 1.7 and check the version java9 folder as well outside. It should have 1.7.
~/java9/subfolder ▶ jenv shell 1.7 ~/java9/subfolder ▶ java -version java version "1.7.0_79" Java(TM) SE Runtime Environment (build 1.7.0_79-b15) Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode) ~/java9/subfolder ▶ cd .. ~/java9 ▶ java -version java version "1.7.0_79" Java(TM) SE Runtime Environment (build 1.7.0_79-b15) Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode) ~/java9 ▶ cd .. ~ ▶ java -version java version "1.7.0_79" Java(TM) SE Runtime Environment (build 1.7.0_79-b15) Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode)
If you open a new shell and run
java -version, it should be global version which 1.8.
We do use other command line utilities like Maven, Ant, gradle and many more. JEnv plugins will allow those command line utilties to recognize java version set by JEnv. To read more about JEnv plugins, check here.
Let’s enable plugins of some commonly used CL tools -
▶ jenv plugins ant export golo gradle grails groovy lein maven sbt scala springboot vlt ~ ▶ jenv enable-plugin maven maven plugin activated ~ ▶ jenv enable-plugin gradle gradle plugin activated ~ ▶ echo $JAVA_HOME ~ ▶ jenv enable-plugin export You may restart your session to activate jenv export plugin echo export plugin activated
Export plugin could be a very useful plguin as it automatically exposes JAVA_HOME variable. JAVA_HOME before activating the plugin was not set. Now, when I open a new shell and check JAVA_HOME at different levels, it matches with Java version set with JEnv. Awesome! Isn’t it?
~ ▶ echo $JAVA_HOME /Users/manik/.jenv/versions/oracle64-184.108.40.206 ~ ▶ cd java9 ~/java9 ▶ echo $JAVA_HOME /Users/manik/.jenv/versions/9
If you don’t see expected results, you can run
One issue I observed is, after setting Java with JEnv my Eclipse was not able to launch. Also, the Anypoint Studio which another eclipse based IDE was not able to work properly and recognize any keyboard clicks/typing. Probably these IDE’s picked up java set by JEnv but faced some issues while locating tools.jar or rt.jar. It could be because the shims generated by JEnv. I did open an issue on github.
To resolve this, I had to provide VM path in eclipse config which is
info.plist on mac -
Having multiple Java versions is so common and managing them is more easier with JEnv.