windowsでデフォルトのjdkのバージョンをカジュアルに切り替える

予防線
----

大分やり尽くされている感あるネタですがメモ程度に。

windows7(x64)での動作を確認しています。それ以外だとどうだろう……。

手順概要
----

1. jdkを適宜入れる
* シンボリックリンクを作る
* 環境変数のPATHをシンボリックリンクに向ける
* system系に置かれたjava実行ファイルを消す
* シンボリックリンクを切り替える


手順
----

#### jdkを適宜入れる

下記リンクからjdkをインストールする。今回はWindows x64版をインストール。

http://www.oracle.com/technetwork/java/javase/downloads/index.html

#### シンボリックリンクを作る

mklink /Dでディレクトリのリンクを作る。管理者権限が必要なので右クリ+管理者として実行でコマンドプロンプトを起動する。

今回はC:\Program Files\Java\latestにjdk1.8.0_45のリンクを作成。

```bat
mklink /D "C:\Program Files\Java\latest" "C:\Program Files\Java\jdk1.8.0_45"
```

#### 環境変数のPATHをシンボリックリンクに向ける

初めて処理系を入れる時のハマりポイントになる環境変数。今回は以下の変更をする。

* システム環境変数のJAVA_HOMEにシンボリックリンクを指定
    * 例の場合だとC:\Program Files\Java\latest
* システム環境変数のPATHに%JAVA_HOME%\bin;を追記する
    * 順番は好きで構わないけど、system32やsysWOW64の指定よりも前(左側)に置くと↓の手続きをやる必要がなくなる

#### system系に置かれたjava実行ファイルを消す

JREを入れた場合にsystem32,sysWOW64にjava.exe,javaws.exe,javaw.exeが入る場合がある。これはなんでも、

* exeファイルの中にバージョンが保持されている
* レジストリ内に保持されているjavaのバージョンと合わないとエラーになる
* バージョン番号を保持しているレジストリ:
    * "HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Development Kit"
    * "HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment"

と言った代物。複数入れる際に厄介になるので消すか優先度を下げる(シンボリックリンクの項参照)。これを機能させたい場合は、切り替える際に上のレジストリのバージョンを変えればOK(だと思う)。

2つのレジストリを1.7に変える例:

```bat
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Development Kit" /v CurrentVersion /t REG_SZ /d 1.7 /f
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment" /v CurrentVersion /t REG_SZ /d 1.7 /f
```


#### シンボリックリンクを切り替える

一度シンボリックリンクを消してからまた付け直す。linuxのそれと同じ？順番はln -sとは逆になってるので注意。あと管理者権限必須。

```bat
rmdir "C:\Program Files\Java\latest"
mklink /D "C:\Program Files\Java\latest" "C:\Program Files\Java\jdk1.7.0_79"
```

これであとはmklinkの先を変えるだけでバージョン切り替えが出来る。らくちん！

バッチを書いてみる
----

``` bat:java7.bat
setlocal
@echo off
set java_dir=C:\Program Files\Java\
set jdk_name=jdk1.7.0_79
set jdk_path=%java_dir%%jdk_name%
set latest_name=latest
set latest_dir=%java_dir%
set latest_path=%latest_dir%%latest_name%
cd %java_dir%
IF EXIST "%latest_path%" (rmdir "%latest_path%") else echo "do not found symlink."
mklink /D "%latest_path%" "%jdk_path%"
pause
endlocal
```

```bat:java8.bat
setlocal
@echo off
set java_dir=C:\Program Files\Java\
set jdk_name=jdk1.8.0_45
set jdk_path=%java_dir%%jdk_name%
set latest_name=latest
set latest_dir=%java_dir%
set latest_path=%latest_dir%%latest_name%
cd %java_dir%
IF EXIST "%latest_path%" (rmdir "%latest_path%") else echo "do not found symlink."
mklink /D "%latest_path%" "%jdk_path%"
pause
endlocal
```

基本的に最初にsetする部分の差だけだし処理の部分は共通部に切っておいてもいいと思う……。

管理者として実行すると以下のようなログが出る。

```
C:\Windows\system32>setlocal
C:\Program Files\Java\latest <<===>> C:\Program Files\Java\jdk1.7.0_79 のシンボ
リック リンクが作成されました
続行するには何かキーを押してください . . .
```

うっかり通常ユーザーとして動かすと……

```
C:\Windows\Users\spamoc>setlocal
アクセスが拒否されました。
この操作を実行するのに十分な特権がありません。
続行するには何かキーを押してください . . .
```

という具合で、何も起こらない。rmdirしてmklinkやってるだけなので、権限ない状態で動かしても大丈夫だし、何度も動かしても大丈夫。削除のパスだけは間違えるとえらいことになるので要注意。


余談
----

実務ではplay2.1系を使っている都合java7を利用していて、同じ環境で勉強としてplay2.4等を触ったりしているので切り替えしたいなーって思うケースはしばしばあります。

単純にIDEで開発しているときは(バージョン指定できるため)影響が出ることはないのですが、playコマンドを動かすときに問題になってきます。

playの話で言うと、コマンド側で明示的に実行するパスを指定するよう変更してしまった方がいいかも知れません。どうせプロキシとか通す必要があった場合書き込んだりしてると思いますし。

仮想化で環境そのものを分けてしまいたい……。


参考資料
----
* WindowsでJDK 7とJDK 8を切り替える際の注意点 - Daregada (だれがだ)
    * http://daregada.blogspot.jp/2015/03/windowsjdk-7jdk-8.html