How to manage multiple Java JDKs in macOS


Many times, when we are compiling and building Mule apps we run into issues because we are using the wrong version of the Java JDK. The problem is that we can’t be uninstalling and installing versions of the JDK every time we’ve got an app or plugin that requires it. We need to have multiple versions of the JDK installed in our laptops and we need to find a quick way to switch between versions. 


In this post, we’ll see how to do that in macOS

Installing Multiple versions of the JDK

First, install different versions of the openJDK with Homebrew:

brew install openjdk@8
brew install openjdk@11
brew install openjdk@22

By default, homebrew install the package into /usr/local/Cellar (for Intel Mac). 
*nix systems search for java under /usr/bin/java, /usr/lib/jvm& /usr/local/bin/java. However, macOS is different, it searches for Java at/Library/Java/JavaVirtualMachines/

If we run list the directory /Library/Java/JavaVirtualMachines we can see there’s nothing in there.

And if we try:
java -version

or the java_home utility in macOS, we see that macOS is not detecting any JDK installation:

/usr/libexec/java_home -V



The Problem with Homebrew

These JDK formulae could have set up the required softlink under folder /Library/Java/JavaVirtualMachines/. But by design, these JDK formulae are kept as keg-only.


If you noticed, during the OpenJDKs installation, this info was also provided in the logs of Homebrew:

For the system Java wrappers to find this JDK, symlink it with
sudo ln -sfn /usr/local/opt/openjdk@11/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-11.jdk

openjdk@11 is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.

If you need to have openjdk@11 first in your PATH, run:
echo 'export PATH="/usr/local/opt/openjdk@11/bin:$PATH"' >> ~/.zshrc

For compilers to find openjdk@11 you may need to set:
export CPPFLAGS="-I/usr/local/opt/openjdk@11/include"

The Solution

We need to do as the logs say and create soft links for each openJDK installation:

sudo ln -sfn /usr/local/opt/openjdk@8/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-8.jdk
sudo ln -sfn /usr/local/opt/openjdk@11/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-11.jdk

Now if we have a look at /Library/Java/JavaVirtualMachines, we can see:


And using the java_home utility:



we can see three installations of the OpenJDK


Switching JDKs

Let’s see a real example in the Mule Dev day-to-day. Maven uses the JAVA_HOME env variable. If we run mvn -version we can see the following:


To switch between various java versions we need to change the JAVA_HOME value to different locations.

We also have /usr/libexec/java_home utility which we will use to move between various versions.

For our installation, this is what the parameter -v (small case v) gives us.


We can leverage the output of this command to set JAVA_HOME as below,
  • export JAVA_HOME=`/usr/libexec/java_home -v 11`

After that, if we check again with Maven:



The command is too long, so we can use some alias
alias java-22="export JAVA_HOME=`/usr/libexec/java_home -v 22`"
alias java-11="export JAVA_HOME=`/usr/libexec/java_home -v 11`"
alias java-8="export JAVA_HOME=`/usr/libexec/java_home -v 1.8`"

Now we just need to type java-11, java-8 or java—2 to switch between versions.

And double check again. We can see how we can change very quickly the OpenJDK for Maven.


Lastly, to make these aliases permanent and available every time we open a new terminal we will add them to the ~/.zshrc file
Previous Post Next Post