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

## 忙しい人のための

設定ファイルに記述する．

`.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}
```

以下詳細．

## はじめに

先日，Java8で遊んでみようと思って，OSX（10.7）にインストールしました．

```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つの方法
OSXでJavaのバージョンを切り替える方法は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バージョンの実体
OSXへJavaを提供する提供元は2箇所あります．AppleとOracleです．

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

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

**JDKの置き場所は2箇所ある．**

## JDKのバージョン切り替え

### 1. `JAVA_HOME`を切り替える
OSXのJavaは次のような項目で環境が決定されるそうです．

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

Java Preferencesは，2012年10月16日にのJavaのセキュリティアップデート（Java for OS X 2012-006）で削除されました． 
これ以降（？），OSXにJavaに提供するのは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
```

## 参考文献

- [How to Revert to Java 1.6 on Mac OS X 10.7.5](http://stackoverflow.com/questions/13594864/how-to-revert-to-java-1-6-on-mac-os-x-10-7-5 )
- [[OS X] [ENV] [JAVA] JAVA SE 7 と JAVA SE 6 との共存](http://hirooka.pro/?p=102)
- [OSXのJava環境切替えのしくみ](http://www.matsuaz.com/matsumotojs/2009/11/17/1258392513883.html)
- [「JavaはOracleから直接入手を」、Apple経由のプラグインに削除措置](http://www.itmedia.co.jp/enterprise/articles/1210/19/news043.html)
- [[Mac][Java] Macで複数のバージョンのJDKを管理する](http://blog.olivinecafe.info/post/59358925622/mac-java-mac-jdk)
- [はてなブログで「Markdown記法一覧」を書いてみるテスト](http://mametanuki.hateblo.jp/entry/2012/09/22/MarkdownList)