Java:ProcessBuilderはどのコマンドを実行するのか?
問題
例えば、Windows上で複数のJRE(仮にJRE8, JRE10とする)をインストールしており、以下のような設定がされているとする。
- レジストリにてJRE8のjavawが指定されている。sample.jarファイルをダブルクリックするとJRE8が動作する。
- PATHにてJRE10のbinフォルダが指定されている。つまり、コマンドラインで単純に「java -jar sample.jar」とすると、JRE10が動作する。
この場合に、ダブルクリックで起動したsample.jar内部においてProcessBuilderを使い、再度「java -jar sample.jar」を実行すると、どういうわけかJRE8が実行されてしまう。PATHで指定されているJRE10ではない。
これは一体どういうわけなのだろうか?
StackOverflowでの事例1
Where does Java’s ProcessBuilder look to execute commands?というやりとりがある。
質問者のケースとしては、ProcessBuilderのPATH変数を潰したのだが、それでもProcessBuilderはコマンドを呼ぶことができるという。一体どうやっているのかという。
回答としては、結局のところ、どうするかはJVM/システムの組み合わせによるので、それに依存するという。しかし、PATH変数を左から右にみていくのではないかという。
別の回答者は、完全にコントロールしたければコマンドの絶対パスを指定しろという。
StackOverflowでの事例2
Java ProcessBuilder can’t find file in PATHというやりとりもある。
ProcessBuilderで”curl”コマンドを呼び出そうとしたが、PATHが通っているにも関わらず呼び出せないという。もちろん、curlの絶対パスを指定すれば呼び出せる。
回答としては、PATH変数からファイルを見つけ出すのは、シェル(あるいはコマンドプロセッサ)の役目だという。だから、ProcessBuilderに”curl”のみで実行させることはできず、自分でPATH変数を解析して絶対パスを取得するしかないということだ。
つまり。。。。
ProcessBuilderはPATHを見ていない。実行させるコマンドについて、その絶対パスを記述しない場合には、「おまかせ」になってしまうということだろうか。。。。
確実に特定のjavaコマンドを実行したい場合
最初に記述した問題についてだが、たとえPATHでJRE10が指定されていても、JRE8のjavawで起動したプログラムでjavaコマンドを呼び出すとJRE8が起動されるという動作は、個人的には希望通りなのだが、この仕様はWindows上だけなのか、あるいは他の環境でもそうなのかが不明だ。
特定のjavaコマンドを呼び出すには、絶対パスにする必要があるのだが、「現在実行されているjavawの絶対パスを知る方法があるか?」と言えば、おそらくこれは”java.home”を見るしか無いだろう。
String home = System.getProperty("java.home");
になる。これが例えば、
C:\Program Files\Java\jdk1.8.0_111\jre
という値になっている。