Java:ProcessBuilderはどのコマンドを実行するのか?

2019年6月14日

問題

例えば、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

という値になっている。