これは、なにをしたくて書いたもの?
JibのFAQを見ていて、こんな1文があることに気づきまして。
For Java 9+, often you may want to use JDK_JAVA_OPTIONS instead of JAVA_TOOL_OPTIONS.
環境変数JAVA_TOOL_OPTIONS
は知っていて、過去にエントリーも書いたことがあるのですが。
環境変数JAVA_TOOL_OPTIONSで、Java VM引数を指定する(-XX:VMOptionsFileも加えて) - CLOVER🍀
JDK_JAVA_OPTIONS
は知りませんでしたね。Java 9以降で使えるようです。
確かにJava 8ではドキュメントに書かれていませんが、
Java 9で現れます。
JDK_JAVA_OPTIONS環境変数
JDK_JAVA_OPTIONS
環境変数が追加されたのは、こちらのようですね。
JAVA_TOOL_OPTIONS
環境変数に関するドキュメントには、JDK_JAVA_OPTIONS
環境変数に対する記述は特にありません。
トラブルシューティング・ガイド / 付録 / C 環境変数とシステム・プロパティ / JAVA_TOOL_OPTIONS環境変数
JDK_JAVA_OPTIONS
環境変数に関する説明は、こちらと
ノート: JDK_JAVA_OPTIONSランチャ環境変数を使用すると、その内容をjavaランチャの実際のコマンド行に付加できます。 「JDK_JAVA_OPTIONSランチャ環境変数の使用方法」を参照してください。
こちらに記載があります。
javaコマンド / JDK_JAVA_OPTIONSランチャ環境変数の使用方法
最初にノートで書かれていたように、java
コマンド向けの環境変数のようです。
説明を見てみましょう。見てみると、コマンドラインで指定した引数の先頭に追加される、ということみたいです。
JDK_JAVA_OPTIONSは、その内容をコマンド行から解析されるオプションの先頭に追加します。 JDK_JAVA_OPTIONS環境変数の内容は、空白文字(isspace()で指定)で区切られた引数のリストです。
空白を含む場合は、引用符で囲みましょう、と。
一重引用符(')または二重引用符(")を使用して、空白文字が含まれる引数を囲むことができます。
また、JDK_JAVA_OPTIONS
環境変数を使って指定できるオプションにはルールがあるようです。
JDK_JAVA_OPTIONSの動作の誤用の可能性を緩和するために、メイン・クラスを指定するオプション(-jarなど)またはメイン・クラスを実行せずにjavaランチャを終了させるオプション(-hなど)は環境変数で指定できません。 このようなオプションのいずれかが環境変数に指定されている場合、ランチャはエラー・メッセージを発行して停止します。
ヘルプなどは指定できないようですね。
指定例。
$ export JDK_JAVA_OPTIONS='-g @file1 -Dprop=value @file2 -Dws.prop="white spaces"' $ java -Xint @file3
これは、以下と等価らしいです。
$ java -g @file1 -Dprop=value @file2 -Dws.prop="white spaces" -Xint @file3
ドキュメントを見るのはこれくらいにして、ちょっと試してみましょう。
環境
今回の環境は、こちらです。
$ java --version openjdk 17.0.3 2022-04-19 OpenJDK Runtime Environment (build 17.0.3+7-Ubuntu-0ubuntu0.20.04.1) OpenJDK 64-Bit Server VM (build 17.0.3+7-Ubuntu-0ubuntu0.20.04.1, mixed mode, sharing)
サンプルプログラム
動作確認には、こちらのプログラムを使うことにします。
App.java
public class App { public static void main(String... args) { System.out.printf("my.prop = %s %n", System.getProperty("my.prop")); } }
JDK_JAVA_OPTIONSとJAVA_TOOL_OPTIONSをちょっと比べる
JDK_JAVA_OPTIONS
環境変数自体を追う前に、まずJAVA_TOOL_OPTIONS
環境変数と比べてみましょう。
JAVA_TOOL_OPTIONS
環境変数を、javac
で利用。
$ JAVA_TOOL_OPTIONS=-verbose javac App.java Picked up JAVA_TOOL_OPTIONS: -verbose [0.002s][info][class,load] opened: /usr/share/java/java-atk-wrapper.jar [0.023s][info][class,load] java.lang.Object source: shared objects file [0.024s][info][class,load] java.io.Serializable source: shared objects file [0.024s][info][class,load] java.lang.Comparable source: shared objects file [0.024s][info][class,load] java.lang.CharSequence source: shared objects file [0.024s][info][class,load] java.lang.constant.Constable source: shared objects file [0.024s][info][class,load] java.lang.constant.ConstantDesc source: shared objects file [0.024s][info][class,load] java.lang.String source: shared objects fil 〜省略〜
使われましたね。
java
コマンド。
$ JAVA_TOOL_OPTIONS='-Xmx1G -Dmy.prop=Hello' java App.java Picked up JAVA_TOOL_OPTIONS: -Xmx1G -Dmy.prop=Hello my.prop = Hello
こちらも有効ですね。
では、JDK_JAVA_OPTIONS
環境変数で試してみましょう。
javac
コマンド。
$ JDK_JAVA_OPTIONS=-verbose javac App.java
こちらには、反応しません。
java
コマンド。
$ JDK_JAVA_OPTIONS='-Xmx1G -Dmy.prop=Hello' java App.java NOTE: Picked up JDK_JAVA_OPTIONS: -Xmx1G -Dmy.prop=Hello my.prop = Hello
ドキュメントに書かれているとおり、JDK_JAVA_OPTIONS
環境変数は確かにjava
コマンドに効果があるようです。
それでは、JDK_JAVA_OPTIONS
環境変数をもうちょっと見てみましょう。
JDK_JAVA_OPTIONS
環境変数をもう少し見てみる
次は、JDK_JAVA_OPTIONS
環境変数とコマンドでの引数指定と同時に行ってみましょう。
$ JDK_JAVA_OPTIONS='-Xmx1G -Dmy.prop=Hello' java -Dmy.prop=World App.java NOTE: Picked up JDK_JAVA_OPTIONS: -Xmx1G -Dmy.prop=Hello my.prop = World
コマンドの引数で指定したものが優先されるようです。
また、こんな話もありましたね。
JDK_JAVA_OPTIONSの動作の誤用の可能性を緩和するために、メイン・クラスを指定するオプション(-jarなど)またはメイン・クラスを実行せずにjavaランチャを終了させるオプション(-hなど)は環境変数で指定できません。
確認してみましょう。
-h
を入れてみます。
$ JDK_JAVA_OPTIONS='-Xmx1G -Dmy.prop=Hello -h' java App.java NOTE: Picked up JDK_JAVA_OPTIONS: -Xmx1G -Dmy.prop=Hello -h Error: Option -h is not allowed in environment variable JDK_JAVA_OPTIONS
エラーになりましたね。確かに指定できないオプションがありそうです。
なにが指定できないオプションなんでしょうね?
エラーメッセージを見てみて
環境変数を参照しているのは、こちらのようです。
エラーメッセージを使っているのは、こちら。
if (NULL == argsInFile) { if (isTerminalOpt(arg)) { if (inEnvVar) { JLI_ReportMessage(ARG_ERROR9, arg, var_name); } else { JLI_ReportMessage(ARG_ERROR15, arg); } exit(1); } JLI_List_add(args, arg);
isTerminalOpt
という関数を見ればよさそうですね。このあたりが対象のオプションみたいですね。
int isTerminalOpt(char *arg) { return JLI_StrCmp(arg, "-jar") == 0 || JLI_StrCmp(arg, "-m") == 0 || JLI_StrCmp(arg, "--module") == 0 || JLI_StrCCmp(arg, "--module=") == 0 || JLI_StrCmp(arg, "--dry-run") == 0 || JLI_StrCmp(arg, "-h") == 0 || JLI_StrCmp(arg, "-?") == 0 || JLI_StrCmp(arg, "-help") == 0 || JLI_StrCmp(arg, "--help") == 0 || JLI_StrCmp(arg, "-X") == 0 || JLI_StrCmp(arg, "--help-extra") == 0 || JLI_StrCmp(arg, "-version") == 0 || JLI_StrCmp(arg, "--version") == 0 || JLI_StrCmp(arg, "-fullversion") == 0 || JLI_StrCmp(arg, "--full-version") == 0; }
--version
も対象のようなので、試してみましょう。
s$ JDK_JAVA_OPTIONS='-Xmx1G -Dmy.prop=Hello --version' java App.java NOTE: Picked up JDK_JAVA_OPTIONS: -Xmx1G -Dmy.prop=Hello --version Error: Option --version is not allowed in environment variable JDK_JAVA_OPTIONS
確かにそのようですね。
ちょっとソースコードを変えてみましょう。
App.java
public class App { public static void main(String... args) { System.out.printf("my.prop1 = %s %n", System.getProperty("my.prop1")); System.out.printf("my.prop2 = %s %n", System.getProperty("my.prop2")); } }
JDK_JAVA_OPTIONS
環境変数と、コマンドの引数でそれぞれ別のものを指定してみます。
$ JDK_JAVA_OPTIONS='-Xmx1G -Dmy.prop1=Hello' java -Dmy.prop2=World App.java NOTE: Picked up JDK_JAVA_OPTIONS: -Xmx1G -Dmy.prop1=Hello my.prop1 = Hello my.prop2 = World
併用できるようです。
とりあえず、こんなところでしょうか?
まとめ
java
コマンドで使える、JDK_JAVA_OPTIONS
環境変数を試してみました。
全然存在に気づいていなかったですね。環境変数で指定するならJAVA_TOOL_OPTIONS
かなと思っていたのですが、java
コマンドを
ターゲットにするならJDK_JAVA_OPTIONS
環境変数を選んだ方が良さそうですね。
覚えておきましょう。