If you, like me, have to deal with multiple projects at different stages, like one being legacy, another one being the latest, and another one being a library or tool consumed by users also using different versions of Java, then you have a small Multiple JDK problem, assuming you only care for one vendor of JDK; otherwise, you have a Matrix JDK problem.
Installing, managing, and switching between JDKs in your computer is no easy task these days where the majority of developers are still on Java 8, while a good chunk is now moving to Java 11. And there are many ways to do that.
This article is to help you through that process.
The Manual Way
You can go after your JDK vendor-of-choice website and download binaries, and install them all manually (or even better just extract them to some folder like $user/jdks and be done with it. But then you have to always verify and update JAVA_HOME to point to the one you really want for this and for that project.
Solutions for this would include using bash scripts, bash functions, and so on. The main problem? You may simply forget to call the script/function, and be hit with some UnsupportedClassVersionError to then only realize what's wrong.
I'll leave this to you to dig the internet for solutions, if you prefer the manual way. For advanced users, it may be the best choice. But I prefer some tooling for this. So, let's dive in:
The Better Way
In my opinion, the ideal way is by combining two open source tools that exist already for quite some time and you may already know at least one of them. What you don't know is that you can combine them.
Let's see how we get them to play ball together…
Install Multiple JDKs
Once you have SDKMAN! installed and configured, you will type:
$ sdk list java
Once you find the vendor and version you want to install, you will type:
$ sdk install java <id>
Let’s add four JDKs, two recent versions of Oracle OpenJDK and two LTS versions by AdoptOpenJDK.
Whenever asked by SDKMAN!, do not set any of them as the default.
- AdoptOpenJDK build of OpenJDK 8u252 — LTS
- AdoptOpenJDK build of OpenJDK 11.0.7 — LTS
- Oracle OpenJDK 14 — Latest GA
- Oracle OpenJDK 15 — Early Access Builds of next release
These four versions should cover you well for legacy projects still stick to Java 8, but also put you in a nice place for modern projects with Java 11 as well as the possibility to experiment new features and enhancements on Java 14 and Java 15.
Alright, you’ve got 4 JDKs installed locally with SDKMAN! —I think this tool is really great for this use case, and I hope you enjoyed it too.
All JDKs installed can be found inside the following directory:
$ cd /Users/bruno/.sdkman/candidates/java$ ls
11.0.7.hs-adpt 14.0.1-open 15.ea.20-open 8.0.252.hs-adpt
Now, if you do want to just use one JDK at all times and not have to switch back and forth, you can use SDKMAN! to set your JDK of choice:
$ sdk current java
Using java version 15.ea.19-open$ sdk default java 15.ea.20-open
Default java version set to 15.ea.20-open
You can stop here and just use SDKMAN! but you will eventually forget to switch back based on the project you are working on, just like by using some manual shell script. And because of this, I prefer to auto-switch.
Manage Multiple JDKs with jEnv
While SDKMAN! can install and manage JDKs, the tool doesn't do a great job at auto-switching between versions for you automatically as you move from project A to project B.
For that, you will want jEnv.
Once you have it installed and configured, and multiple JDKs, whether with SDKMAN! or some other way, you will need to add those JDKs to jEnv. Here’s how:
$ cd ~/.sdkman/candidates/java$ ls -1
8.0.252.hs-adpt$ jenv add 15.ea.20-open
15-ea added...$ jenv versions
* 15-ea (set by /Users/bruno/.jenv/version)
Repeat the command jenv add for all other 3 versions.
jEnv has excellent features especially for those constantly using terminals. It will allow you to:
- Set a Java version for your overall system.
- Set a Java version for the current directory/project you are in.
- Set a Java version for the current shell.
jEnv uses shim binaries and also manipulates the JAVA_HOME environment variable for you automatically. So, once you have these settings, jEnv will switch to whatever version makes most sense, based on the priority above and based on where you are. Neat! It has other nice features, so check the website for more documentation.
Auto-Switch Between Multiple JDKs
Now you have Java 8, 11, 14 and 15-EA available. So how do you switch back and forth? Let's set versions and switch back and forth.
First you set a Java version to be global default. I like to use an Early Access as my system default. Whenever I hit a new project, I will automatically attempt to work with an upcoming release, and this could help me identify potential problems I can then report back to the OpenJDK project. But you do you…
$ jenv global 15
With this setting, whenever you hit any folder on your terminal and you type java -version you will get OpenJDK 15 EA.
If you do have a project that must use Java 8, then you navigate to that project folder, and you type:
$ jenv local 1.8
This will create a file called .java-version with the following content:
$ cat .java-version
│ File: .java-version
1 │ 11.0
This file is what tells jEnv which JDK to use for when the terminal is on this folder.
Finally, if you are on some location and you want to temporarily switch to a specific JDK version, then you use jenv shell.
Here's a demonstration that can explain better all these concepts and how the Auto-Switch works:
I hope you enjoyed the read, and if you have questions, just reach out to me on Twitter.
** Update May 2020
As usual, this article has obtained quite some interesting feedback and comments from users. I also posted on Reddit and also got some interesting responses.
There are other tools that you should be aware:
- SDKMAN! now supports sdk env, with auto-switch now available since May 4th in version 5.8.1+.
- direnv is very nice as it is agnostic but covers exactly what jEnv is designed for, except it doesn't help you with the ease of switching between JDKs. You have to edit files manually.
- autoenv is just another alternative to direnv with the same limitations.
- jabba is the most promising alternative to a combo SDKMAN+jEnv as it supports all use cases and also works on Windows (PowerShell), something that none of the options above support.
There you have it :-)