OSXでJavaのバージョンを切り替える

先日,Java8で遊んでみようと思って,OSXにインストールしました.

java -versionを打つと

java version "1.8.0-ea"
Java(TM) SE Runtime Environment (build 1.8.0-ea-b121)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b63, mixed mode)

がでて,ちゃんと1.8になってるなよしよし.
と思って生活してたんだけども,思わぬところで事故ったので,1.6に戻す事にしました. でも,いじっているうちに良くわからなくなったので,ログとしてやったことをまとめておこうと思います.

Javaのバージョンを切り替える2つの方法

OSXJavaのバージョンを切り替える方法は2つ(しか知らない)あります.

  1. JAVA_HOMEを切り替える
  2. 非推奨: /System/Library/Frameworks/JavaVM.framework/Versionsの下のCurrentJDKを切り替える

javaコマンドの実体

まず,1.8をインストールした後,which javaを打つと,/usr/bin/javaが返ってきます. 実は,シンボリックリンクなのでls -l /usr/bin/javaでリンク先を見てみると,

java -> /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java

という結果が返ってきます. javaコマンドだけではなく,javacなどのコマンドも/System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands下にあるものを指してます.

MacOSXにおけるjavaのバージョンについて

Mac OSXのJavaのバージョンは一応/System/Library/Frameworks/JavaVM.framework/Versionsで管理(?)されています(本当か?).

ここの,ディレクトリをみてみると,

$ ls -l /System/Library/Frameworks/JavaVM.framework/Versions
total 40K
lrwxr-xr-x 1 root wheel  10  8 27 12:53 1.4 -> CurrentJDK/
lrwxr-xr-x 1 root wheel  10  8 27 12:53 1.4.2 -> CurrentJDK/
lrwxr-xr-x 1 root wheel  10  8 27 12:53 1.5 -> CurrentJDK/
lrwxr-xr-x 1 root wheel  10  8 27 12:53 1.5.0 -> CurrentJDK/
lrwxr-xr-x 1 root wheel  10  8 27 12:53 1.6 -> CurrentJDK/
lrwxr-xr-x 1 root wheel  10  8 27 12:53 1.6.0 -> CurrentJDK/
drwxr-xr-x 9 root wheel 306  1 27 18:57 A/
lrwxr-xr-x 1 root wheel   1  1 28 12:39 Current -> A/
lrwxr-xr-x 1 root wheel  59  8 27 12:53 CurrentJDK -> /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/

となっています.

ん?1.4も1.5も1.6もCurrentJDKを指してます. CurrentJDKは,/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/を指しています. つまり,バージョン1.4も1.5も,実は1.6だったということ.

Javaバージョンの実体

OSXJavaを提供する提供元は2箇所あります.AppleOracleです.

Appleが提供しているJavaは,CurrentJDKの指している/System/Library/Java/JavaVirtualMachinesに格納されています.

また,Oracleが提供しているパッケージを使って1.7や1.8をインストールした場合は, /Library/Java/JavaVirtualMachinesになります.

JDKの置き場所は2箇所ある.

JDKのバージョン切り替え

1. JAVA_HOMEを切り替える

OSXJavaは次のような項目で環境が決定されるそうです.

  1. Java Preferencesの優先順位をみて決定する
  2. 環境変数JAVA_HOMEが設定してある場合はこちらを優先する

Java Preferencesは,2012年10月16日にのJavaのセキュリティアップデート(Java for OS X 2012-006)で削除されました. これ以降(?),OSXJavaに提供するのはAppleからOracleに変わったようです. どちらにせよ,JAVA_HOMEを設定して上書きしてしまえばバージョンは変更できそうです.

このバージョンのパスを返す便利なコマンドが実は存在します.

java_home コマンド

このコマンドは,指定したJavaバージョンのhomeがどこにあるかを返すコマンドです. 配置されている場所は,/System/Library/Frameworks/JavaVM.framework/Versions/A/Commandsです. 実行するとこんな感じになります.

$ ./java_home -v "1.4"
Unable to find any JVMs matching version "1.4".
/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home
$ ./java_home -v "1.5"
Unable to find any JVMs matching version "1.5".
/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home
$ ./java_home -v "1.6"
/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
$ ./java_home -v "1.7"
Unable to find any JVMs matching version "1.7".
/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home
$ ./java_home -v "1.8"
/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home

1.6と1.8しかインストールしてないので,1.4,1.5と1.7は最新である1.8を指します. 1.6だけはインストールされているので,ちゃんと1.6のパスが返ってきます.

設定ファイルに記述する

.profile, .bashrc, .zshrcなどなんでもいいですが,どれかで,環境変数JAVA_HOMEに設定します. さきほどのjava_homeコマンドを使います.

export JAVA_HOME=`/System/Library/Frameworks/JavaVM.framework/Versions/A/Commands/java_home -v "1.6"`
PATH=${JAVA_HOME}/bin:${PATH}

以降,1.6の部分を,1.8に変えると簡単にバージョンを切り替えることができます.


2. 非推奨?: /System/Library/Frameworks/JavaVM.framework/Versionsの下のCurrentJDKを切り替える

この方法は,OSX標準の構造を色々といじるので,いつ,どこで,どんな事件が起こるかわかりません. そのため,個人的には非推奨です. アンチパターン?として,一応紹介しておきます.

まず,/System/Library/Frameworks/JavaVM.framework/Versionsにある,1.6以前のバージョンを整理します.

1.4 -> CurrentJDK/
1.4.2 -> CurrentJDK/
1.5 -> CurrentJDK/
1.5.0 -> CurrentJDK/
1.6 -> CurrentJDK/
1.6.0 -> CurrentJDK/
CurrentJDK -> /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/

CurrentJDKをバシバシ切り替えたいので,1.4と1.5の向き先を1.6にします. (上書きしようと思ったけれども,-f,Fつけても上書きされなかった..)

sudo rm 1.4;   sudo ln -sf 1.4.2 1.4
sudo rm 1.4.2; sudo ln -sf 1.5 1.4.2
sudo rm 1.5;   sudo ln -s 1.5.0 1.5
sudo rm 1.5.0; sudo ln -s 1.6 1.5.0
sudo rm 1.6;   sudo ln -s 1.6.0 1.6
sudo rm 1.6.0; sudo ln -s /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents 1.6.0
sudo rm CurrentJDK; sudo ln -s 1.6 CurrentJDK

次に,1.8を入れたので1.8用のリンクを追加します.

ln -s /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents 1.8.0
ln -s 1.8.0 1.8

すると,こういう構成になります.

$ ls -l
total 40K
lrwxr-xr-x 1 root wheel   5  1 28 16:39 1.4 -> 1.4.2/
lrwxr-xr-x 1 root wheel   3  1 28 16:40 1.4.2 -> 1.5/
lrwxr-xr-x 1 root wheel   5  1 28 16:45 1.5 -> 1.5.0/
lrwxr-xr-x 1 root wheel   3  1 28 16:45 1.5.0 -> 1.6/
lrwxr-xr-x 1 root wheel   5  1 28 16:46 1.6 -> 1.6.0/
lrwxr-xr-x 1 root wheel  59  1 28 16:47 1.6.0 -> /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/
lrwxr-xr-x 1 root wheel   5  1 28 15:27 1.8 -> 1.8.0/
lrwxr-xr-x 1 root wheel  55  1 28 15:26 1.8.0 -> /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/
drwxr-xr-x 9 root wheel 306  1 27 18:57 A/
lrwxr-xr-x 1 root wheel   1  1 28 12:39 Current -> A/
lrwxr-xr-x 1 root wheel   3  1 28 16:50 CurrentJDK -> 1.6/

CurrentJDKの向き先を1.8や1.6にすると切り替えられるようになりました.

javaコマンド

この状態でjava -versionコマンドを実行すると,まだ1.8のjavaが実行されてます. Current -> A下のCommand下にあるjavaコマンドを実行しています(Aってなんだ...).

Aの中身は,

$ ls -l A
total 40K
lrwxr-xr-x  1 root wheel    3  1 27 18:57 1.6 -> 1.6
drwxr-xr-x 44 root wheel 1.5K  8 27 12:53 Commands/
drwxr-xr-x  4 root wheel  136 11 18  2011 Frameworks/
drwxr-xr-x 14 root wheel  476  3 29  2013 Headers/
-rwxr-xr-x  1 root wheel 102K  8 27 12:53 JavaVM*
drwxr-xr-x 42 root wheel 1.4K  8 27 12:53 Resources/
drwxr-xr-x  3 root wheel  102  8 27 12:53 _CodeSignature/

のようになっています. 1.6のシンボリックリンクは無限ループになってます.

おそらく,1.8をインストールすると, /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/binにあるコマンドが, /System/Library/Frameworks/JavaVM.framework/Versions/A/Commandsにコピーされているような気がします. なので,これもシンボリックリンクで参照してあげます.

sudo mv Commands Commands.back
sudo ln -s /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home/bin Commands

おまけ

はてなブログのMarkdownって脚注([^1])とかうまくやってくれないんですね.

参考文献