Manage your Java JDKs
Pro tip for anyone working with any programming language: Find a clean and easy way to switch versions of your programming language of choice.
All it takes is a CI environment running a different version of your programming language and the world goes Pete Tong.
My approach is to use a language version manager. If you're using JavaScript, nvm is a great option, Ruby has rvm and for Clojure developers we have tools.deps for managing versions of Clojure and jEnv for managing our JDKs.
Why Version Management Tools
Version management tools allow us to quickly and easily manage (add, switch, remove et al.) the version of our programming languages. This enables us to easily test our code against different languages. Example scenarios where I've had to switch language versions:
- Debugging CI environments
- Resolving "works on my machine" issues
- Regression testing an app or library against an older version of a language
- Switching between multiple projects with different language version requirements
The need to do this exists with all programming languages. Some languages
are easier to do this with than others. For example, with Clojure you don't
need a tool, you just use tools.deps to specify the version of the language
you want to use. With Java, it's more complicated so I use a tool called jEnv
.
jEnv
is a tool that allows you to manage your Java JDK installations. It
you switch between versions of the JDK. One thing to note is that this tool
does not allow you to install a JDK. You have to do this separatley. Further,
while it's straightforward to setup jEnv
, there are some gotchas
which is why i'm writing this guide.
Install jEnv
The first thing we have to do is install jEnv
.
brew install jenv
and now let's do a sanity check to see if it's installed correctly. Run:
jenv doctor
and if the above worked you should see something like this:
[ERROR] Java binary in path is not in the jenv shims.
[ERROR] Please check your path, or try using /path/to/java/home # ...
[ERROR] Jenv is not loaded in your zsh
[ERROR] To fix : cat eval "$(jenv init -)" >> /Users/# ...
Configure jEnv
Assuming the above worked, we can now configure jEnv
. The next step is to
add jEnv
to our PATH
by updating our configuration file.
To do this, you need to know which shell
you're running. Type the following
into your terminal to figure out the shell
you're running:
echo $0
If you are using bash
, the above will print out -bash
and if you're using
zsh
the above will print out -zsh
. Once you discover which shell
you are
using, please choose the associated code block below and run the code inside of
it line by line:
zsh shell
echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(jenv init -)"' >> ~/.zshrc
bash shell
echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(jenv init -)"' >> ~/.bashrc
Now we can once again run a sanity check:
jenv doctor
Which will return something like this:
[OK] No JAVA_HOME set
[ERROR] Java binary in path is not in the jenv shims.
[ERROR] Please check your path, or try using /path/to/java/home #...
[OK] Jenv is correctly loaded
As you can see, we now have two less errors. We're making progress! From here, we want to run the following:
jenv enable-plugin export
exec $SHELL -l
and now running jenv doctor
returns this:
[OK] JAVA_HOME variable probably set by jenv PROMPT
[ERROR] Java binary in path is not in the jenv shims.
[ERROR] Please check your path, or try using /path/to/java/home #...
[OK] Jenv is correctly loaded
At this point, jEnv
is setup and the last item on our list is to install a
Java JDK. If you don't have one installed checkout Adoptium
Add a JDK to jEnv
Not sure if you have a Java JDK installed? No worries, we'll find out together!
Run the following command in your terminal to see which Java JDKs we have installed.
/usr/libexec/java_home -V
and that will print something like this:
Matching Java Virtual Machines (2):
21.0.3 (arm64) "Eclipse Adoptium" - "OpenJDK 21.0.3" /Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home
17.0.11 (arm64) "Eclipse Adoptium" - "OpenJDK 17.0.11" /Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home
/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home
If you see something like the above, it means you have at least one Java JDK installed and you can continue on with this section.
Now we can go ahead and add JDK's to jEnv
so it can manage them for us. Run the following command
jenv add /Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home
When you run the above, you will see something like this returned:
temurin64-21.0.3 added
21.0.3 added
21.0 added
21 added
As a sanity check, we can run jenv versions
to see if jEnv
knows about our JDK:
* system (set by /Users/username/.jenv/version)
21
21.0
21.0.3
temurin64-21.0.3
Great, but remember how I have two JDK's installed? The above indicates that
only one of them is being managed by jEnv
. This means I have to run through
the above step again to have jEnv
know about the other version of the JDK I
have installed. So, let's repeat those steps:
jenv add /Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home
again we get our success output
temurin64-17.0.11 added
17.0.11 added
17.0 added
17 added
and when we check versions available now by running jenv versions
we have both 11 and 13 available to us:
* system (set by /Users/username/.jenv/version)
17
17.0
17.0.11
21
21.0
21.0.3
temurin64-17.0.11
temurin64-21.0.3
Set a JDK version via jEnv
As a final step, we want to actualy set a JDK to be the one we use. You have two options for this: jenv local
and jenv global
.
jenv local
is going to set your JDK of choice for your current terminal session. jenv global
is going to set your chosen JDK as the default for all terminal sessions. For now, let's set a global version. In my case, i'm going to set my jenv global
to AdoptOpenJDK 11
like this:
jenv global 21.0.3
Now, in order for the above to take effect, we have to open a new terminal window. Once you open a new terminal window run the following command to be sure our specified version of Java was set:
java -version
and you should see something like this:
openjdk 21.0.3 2024-04-16 LTS
OpenJDK Runtime Environment Temurin-21.0.3+9 (build 21.0.3+9-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.3+9 (build 21.0.3+9-LTS, mixed mode)
That's everything involved in setting a global
version of JDK through jEnv
.
Uninstalling Jenv
If for any reason you feel like something went wrong while installing jenv
, or maybe you just don't like jEnv
and you want to cleanup your environment the following steps will help you remove it.
brew uninstall jenv
Remove the .jenv
directory
rm -rf ~/.jenv
remove the PATH
and init script we added to our shell (either bash
or zsh
)
That's everything involved in setting up and working with Jenv. I hoped this helped.