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!

The problem?

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 -

What is JEnv?

And it does what it says, helps you manage your java environment.

As far as I know, this JEnv is different than JEnv.io.

Install JEnv

JEnv website has good installation details but here are quick steps for Mac OSX -

  • Install using Homebrew - brew install jenv

  • Configure bash

    echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.bash_profile
    $ echo 'eval "$(jenv init -)"' >> ~/.bash_profile
  • Run jenv on 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
  1.7.0.79
  1.8
  1.8.0.131
  9
  oracle64-1.7.0.79
* oracle64-1.8.0.131 (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.

Global Java

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-1.8.0.131

Local Java

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 Java

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.

JEnv Plugins

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-1.8.0.131

~
▶ cd java9

~/java9
▶ echo $JAVA_HOME
/Users/manik/.jenv/versions/9
If you don’t see expected results, you can run jenv rehash for JEnv to recompute everything and consider your new settings. I had to do it after I enabled plugins.

Issues

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 -

<string>-vm</string><string>/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/bin/java</string>

Conclusion

Having multiple Java versions is so common and managing them is more easier with JEnv.

References

on twitter to get updates on new posts.

Stay updated!

On this blog, I post articles about different technologies like Java, MuleSoft, and much more.

You can get updates for new Posts in your email by subscribing to JavaStreets feed here -


Lives on Java Planet, Walks on Java Streets, Read/Writes in Java, JCP member, Jakarta EE enthusiast, MuleSoft Integration Architect, MuleSoft Community Ambassador, Open Source Contributor and Supporter, also writes at Unit Testers, A Family man!