Support multiple JDKs in Debian Linux

With the relatively recent change in the frequency of Java releases (every six months) it has become pretty much required to be able to have multiple JDKs on one’s development machine, and being able to run/test them at different times, for different projects, or even for the same project.

Motivation

While some wizardry with symlinks and similar hackery is possible, on Ubuntu the alternatives system allows a relatively simpler approach.

If one contents oneself with simply having java and javac with alternatives[0], it is simply a matter of running something like:

sudo update-alternatives --install /usr/bin/javac javac \
    /usr/lib/jvm/jdk-10.0.2/bin/javac 1010

assuming that one has untarred the OpenJDK tarball for JDK 10 in the above directory (and similarly for javac) [1].

However, the whole JRE/JDK package contains in excess of 20 binaries, and having a mish-mash of them is a sure recipe for disaster (best case scenario: weird issues and time wasted chasing red herrings).

A much better alternative is to use update-java-alternatives; however:

  1. this requires a laborious process of “configuring” the binaries; and
  2. it needs a .jinfo file, which is largely undocumented and no longer a part of the OpenJDK distribution [2]

To overcome both limitations I have created this shell script that takes a JDK distribution, untarred in /usr/lib/jvm and sets it up as the current JDK.

Usage

Once you have downloaded, for example, OpenJDK 15 and extracted to /usr/lib/jvm you will have something like the following:

$ ll /usr/lib/jvm
total 12K
lrwxrwxrwx 1 root  root    25 Jul 17  2019 default-java -> java-1.11.0-openjdk-amd64
lrwxrwxrwx 1 root  root    10 Dec 28 21:57 java-1.11.0-openjdk-amd64 -> jdk-11.0.2
lrwxrwxrwx 1 root  root    21 Oct 10  2019 java-1.14.0-openjdk-amd64 -> java-14-openjdk-amd64
drwxr-xr-x 9 root  root  4.0K Nov  2 18:47 java-14-openjdk-amd64
drwxrwxr-x 8 marco marco 4.0K Dec 28 21:47 jdk-11.0.2
drwxrwxr-x 8 marco marco 4.0K Dec 28 12:12 jdk-15.0.1

If OpenJDK 14 is your current JDK:

$ java -version                         
openjdk version "14.0.2" 2020-07-14
OpenJDK Runtime Environment (build 14.0.2+12-Ubuntu-120.04)
OpenJDK 64-Bit Server VM (build 14.0.2+12-Ubuntu-120.04, mixed mode, sharing)

using update-alternatives will show the two currently available options:

$ update-alternatives --config java     
There are 2 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                                         Priority   Status
------------------------------------------------------------
* 1            /usr/lib/jvm/java-14-openjdk-amd64/bin/java   1411      auto mode
  2            /usr/lib/jvm/jdk-11.0.2/bin/java              1100      manual mode

Press <enter> to keep the current choice[*], or type selection number:

the priority column also shows that 14 is the highest (hence, preferred) (the one that would be selected using --auto).

To add JDK 15 to the list of available alternatives, setting it as the preferred (highest priority) and configuring it to be the currently selected one, simply run:

$ ./update-jdk jdk-15.0.1 1500

$ update-alternatives --config java   
There are 3 choices for the alternative java (providing /usr/bin/java).

  Selection    Path                                         Priority   Status
------------------------------------------------------------
* 0            /usr/lib/jvm/jdk-15.0.1/bin/java              1500      auto mode
  1            /usr/lib/jvm/java-14-openjdk-amd64/bin/java   1411      manual mode
  2            /usr/lib/jvm/jdk-11.0.2/bin/java              1100      manual mode
  3            /usr/lib/jvm/jdk-15.0.1/bin/java              1500      manual mode

Press <enter> to keep the current choice[*], or type selection number:

$ java -version                         
openjdk version "15.0.1" 2020-10-20
OpenJDK Runtime Environment (build 15.0.1+9-18)
OpenJDK 64-Bit Server VM (build 15.0.1+9-18, mixed mode, sharing)

You will also note that there is a new /usr/lib/jvm/.jdk-15.0.1.jinfo file, which lists all the binaries that come with the JDK and they all point to the right place [1].

Switching across JDK versions

Once installed for the first time (or even subsequent times) it is best to use the update-java-alternatives command, with the name of the JDK one wants to activate; given the above folder structure:

$ sudo update-java-alternatives --set jdk-11.0.2

will do the needful:

$ java -version                                 
openjdk version "11.0.2" 2019-01-15
OpenJDK Runtime Environment 18.9 (build 11.0.2+9)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode)

while using update-java-alternatives --auto will simply pick the highest priority JDK (in the example above, JDK 15).

WARNING using update-alternatives --config java will naturally work, but only for the java binary (/usr/bin/java) while leaving the other binaries pointing to whatever the current JDK is (e.g., javac may still be pointing to the JDK 14) — this is something that is unlikely to cause happiness.

Notes

[0] Regretfully, a lot of the “tutorials” you find online are written by folks who don’t really understand the topic, and will only get you to change the symlinks for java and javac (if you are lucky, javadoc too, perhaps) – which, again, works most of time; until it doesn’t.

[1] The symlinks are in the /etc/alternatives directory, and are pointed to from /usr/bin/java, ‘/usr/bin/javac’, etc.

[2] If it ever was – I have not been able to find it, but a couple were in my /usr/lib/jvm, although I have no idea how they wound up there; those are what I used as a guide, even though the “official” documentation of update-java-alternatives (dating back to 2006) is not consistent with the current format.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s