大パッケージ製品開発担当の大です。師走に入り、すっかり寒くなりましたね。今回は、JavaのRumtime.execのお話をしようと思います。Update21でのこの変更でした。array.Windows上でのRuntime.execの動きが変わったということで、結構あちこちで話題になっていましたので、ご覧になった方も多いんじゃないでしょうか。見るからにやばそうな変更で、実際そのとおりでした。前準備Runtime.execの動きがどう変わったのか。検証する前準備として、以下のようなWin32アプリケーションを用意しました。これをRuntime.execで起動して、動きをみようという目論見です。EXIT_SUCCESS;}渡されたコマンドライン引数を"{"と"}"で囲って標準出力に出力するだけです。実行してみるとこんなかんじになります。}(ここでmoreにパイプしてるのは、Win32アプリはそのままだと標準出力をコンソールに吐かないからです)コマンドライン引数がダブルクォートまで含めてそのままアプリケーションに渡ってきているのがわかりますね。.NETでは事情が違いますが、Win32ではコマンドライン引数のパースはこのようにアプリケーションに丸投げされていたのです。このため、Win32アプリに引数を渡す場合には、ダブルクォートまで含めて正確に渡さないと意図したとおり動かない可能性があるのです。それが良いか悪いかはまた別の話。このへんの話も参考になります。いう「空白を含む」フォルダにコピーしておきます。このフォルダを環境変数PATHに追加して、絶対パス指定じゃなくてもexeが動くようにしておきます。Update17以前での動きまずはUpdate17(21のひとつ前のバージョン)で、これまでの動きを確認してみます。F"の4つを考えます。こんなかんじでSpockでテストを書きました:動作確認(クリックで拡大)(等幅フォントがない環境でも綺麗に見られるように画像にしています)実行してみると、期待どおり動作します。Runtime.exec(String[])さて、Update21での変更を確認します。Runtime.exec(String)で空白を含むコマンドは使えなくなってるから、Runtime.exec(String[])使ってね、ということでした。先ほどのテストを動かして確認してみます。Update21での実行結果(クリックで拡大)そのとおりですね。コマンドと引数を配列に分割して渡すようにしてみましょうか。コマンドと引数を配列で渡す(クリックで拡大)実行結果(クリックで拡大)ダメですね。余計なダブルクォートで囲まれて渡されてしまっています。実はこの動作はUpdate17以前でも同じでした。[])を使わず、Runtime.exec(String)を使っていた人も多いのではないでしょうか。✕ということで、「コマンドも引数も空白を含む場合」には動作させる手段がなくなってしまいました。allowAmbigousCommandsとセキュリティマネージャ4月のUpdate21のリリースにつづいて、6月にUpdate25がリリースされました。ここでもRuntime.execがリリースノートに載っています:http://www.oracle.com/technetwork/java/javase/7u25-relnotes-1955741.html#jruntime要約すると、jdk.lang.Process.allowAmbigousCommandsというプロパティが追加されました。trueに設定すると、昔の動作に戻します。SecurityManager不使用の場合のみ動作します。このプロパティの有・無を追加して、Runtime.exec(String)を試してみます。✕というわけで、Update25でRuntime.exec(String)使う場合、SecurityManagerが指定されていない環境なら、allowAmbigousCommands=trueを指定すればUpdate17以前のように動くようになりました。スペルミスとデフォルト値の変更さて、Update25で導入されたallowAmbigousCommandsですが、リリース後にこんなチケットがあがりました。http://bugs.sun.com/view_bug.do?bug_id=8017467・・・スペルミス!?これにより、プロパティ名がallowAmbigousCommandsからallowAmbiguousCommandsに変更されました。allowAmbigousCommandsに値を設定しても無視されます。http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8016046ということで、allowAmbigousCommandsのデフォルト値はfalseだったのが、allowAmbiguousCommandsのデフォルト値は(SecurityManager不使用の場合は)trueになりました。✕これらの変更が9月にリリースされたUpdate40で入ったのですが、今回はリリースノートには書かれておらず、バグフィックスとしてさらっと掲載されているだけなので、見落としている人も多いかもしれません。最後にというわけで、いくつかの変遷はありましたが、Update40以降はSecurityManagerが設定されていなければデフォルトでUpdate17以前の動作をするようになりました。Update21や25で解決できない問題にぶつかったら、素直にUpdate40以降にアップデートするのが良いと思います。Java界隈は最近、言語仕様やライブラリも他の言語に負けないように急ピッチで機能強化されていっているように思います。それはそれで嬉しいんですが、やっぱり自分個人としてはJavaに求めるものって「固さ」なんですよね。今回の件は、互換性を失いかねない変更やその後の修正があまりにも軽く行われているようで、調査しながらなんだかちょっと残念な気分になったのでした。開発者ブログの内容は無保証です。製品のユーザサポート対象ではありません。