jenvで複数バージョンのJDKを切り替える

仕事でJava 8とJava 11を行ったり来たりしたり、Javaの特定のマイナーバージョンでのみ発生する問題の調査などをしないといけないケースが出てきて、最初は都度環境変数で切り替えていたのですが、切り替え忘れてうっかり別のバージョンでコンパイルしてしまうということが増えてきたのでjenvというツールを試してみました。

github.com

Macの場合はbrewでインストールできます。

$ brew install jenv

jenvはデフォルトでは~/.jenvに設定などを保存するようです。以下のディレクトリを手動で作成しておく必要がありました。*1

$ mkdir -p ~/.jenv/versions

.bash_profileなどに以下を追加。

eval "$(jenv init -)"

JDKbrew caskでインストールできるようなのですが、手元にはすでにインストールしたものがあるのでとりあえずそれを追加してみます。

$ /usr/libexec/java_home -V
Matching Java Virtual Machines (1):
    1.8.0_181, x86_64:  "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home

/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home

jenv addコマンドでjenvにJDKを認識させます。

$ jenv add /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home

手動でダウンロードしたGraalVMとJava 11も追加してみます。

$ jenv add /Users/takezoe/Downloads/graalvm-ce-java8-20.0.0/Contents/Home
$ jenv add /Users/takezoe/Downloads/amazon-corretto-11.jdk/Contents/Home

これで準備完了です。jenv versionsでjenvが認識しているJDKが一覧表示されます。GraalVMは普通のOpenJDKと区別が付かなくて紛らわしい感じがありますね…。

$ jenv versions
* system (set by /Users/takezoe/.jenv/version)
  1.8
  1.8.0.181
  1.8.0.242
  11.0
  11.0.7
  openjdk64-1.8.0.242
  openjdk64-11.0.7
  oracle64-1.8.0.181

jenv global <version>で使用するバージョンをグローバルに切り替えます。JDKのインストールは自分で行う必要がありますが、一度JDKを認識させてしませば使い勝手はpyenvやrbenvと同じような感じです。

$ jenv global 1.8.0.181

特定のディレクトリだけ別のバージョンを使用するには当該のディレクトリでjenv local <version>を実行します。この場合、ディレクトリに.java-versionというファイルが生成されます。このファイルをGitにコミットしておけばブランチごとに使用するJavaのバージョンが異なる場合でも自動で切り替えることができますね。

$ jenv global 11.0.7

jenvでのバージョン切り替えに応じて環境変数JAVA_HOMEも切り替えるには以下のコマンドを使用してexportプラグインを有効にしておく必要があるようです。

$ jenv enable-plugin export

SDKMANでも複数バージョンのJDKの切り替えができ、こちらはJDKのインストールもできるようですが、ざっとドキュメントを見たところでは「特定のディレクトリのみこのバージョンを使う」という設定ができるかどうかわかりませんでした。ひとまずjenvをしばらく使ってみようと思います。

追記:jenvでJDKディストリビューションの区別が付かないという問題は最新のmasterブランチでは修正されており、jenv addでprovider付きのエイリアスも登録されるようになっていました。ただ、この修正を含むバージョンはまだリリースされていないようで、Homebrewでインストールすることはできません。

*1:追記: 2022年10月現在Homebrewでインストール可能なバージョンでは手動でディレクトリを作成する必要はありませんでした。