- JAVA
InaccessibleObjectExceptionの直し方|Java 17
java.lang.reflect.InaccessibleObjectException: Unable to make field ... accessible: module java.base does not "opens java.util" to unnamed module は、プログラム(またはライブラリ)が、リフレクションで JDK の内部の private なフィールドを使おうとして、JDK 17 以降で拒否されたときの例外です。
Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make field transient java.lang.Object[] java.util.ArrayList.elementData accessible: module java.base does not "opens java.util" to unnamed module @2a139a55
JDK 11 までは警告だけで動いていたコードが、JDK 17 に上げたとたんに止まるのが典型です。
| 直し方 | 内容 | 向いている場面 |
|---|---|---|
| ① 原因のライブラリを新しい版にする | スタックトレースから、リフレクションを使っているライブラリを探す | まず検討する。根本的な解決 |
② --add-opens で、その package だけ開ける |
--add-opens java.base/java.util=ALL-UNNAMED |
すぐに動かす必要があるとき(一時しのぎ) |
| ③ 自分のコードなら、内部のフィールドを使わない | 公開されているメソッドで書き直す | 自分で書いたリフレクション |
確認環境:OpenJDK 8・11・17・21・25 で、ArrayList の private フィールド elementData を setAccessible(true) する同じ class ファイルを動かしました(確認日 2026年10月11日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「InaccessibleObjectExceptionの直し方|Java 17」
JDK の版で、動きが変わる
Field f = ArrayList.class.getDeclaredField("elementData");
f.setAccessible(true); // ← JDK 17 以降はここで例外
| JDK | 結果 |
|---|---|
| 8 | 動いた(警告なし) |
| 11 | 動いたが、WARNING: An illegal reflective access operation has occurred などの警告が出た |
11 で --illegal-access=deny |
InaccessibleObjectException |
| 17・21・25 | InaccessibleObjectException |
17 で --illegal-access=permit |
Ignoring option --illegal-access=permit; support was removed in 17.0 と表示され、例外のまま |
JEP 403 により、JDK 17 から JDK の内部は強くカプセル化され、--illegal-access で以前の動きに戻すことはできなくなりました(JEP 403 では、JDK 16 で既定が deny になったことも説明されています)。JDK 11 のときに出ていた illegal reflective access の警告は、JDK 17 で止まる場所の予告です。
エラー文から --add-opens の書き方を作る
module java.base does not "opens java.util" to unnamed module
~~~~~~~~~ ~~~~~~~~~~~~ ~~~~~~~~~~~~~~
モジュール package 開ける相手
| エラー文の部分 | --add-opens での書き方 |
|---|---|
module java.base |
java.base/ |
opens java.util |
java.util |
to unnamed module |
=ALL-UNNAMED(クラスパスで動かしているコード全体) |
java --add-opens java.base/java.util=ALL-UNNAMED -jar app.jar
| 指定 | 結果(JDK 21) |
|---|---|
--add-opens java.base/java.util=ALL-UNNAMED |
動いた |
--add-opens java.base/java.lang=ALL-UNNAMED(package 違い) |
例外のまま |
エラー文の opens ○○ の package と、同じ package を指定します。 別の package で同じエラーが続くときは、エラー文が変わるので、1つずつ足していきます。
--add-opens を渡す方法
| 方法 | 書き方 | 確認環境の結果 |
|---|---|---|
| java コマンドの引数 | java --add-opens java.base/java.util=ALL-UNNAMED ... |
動いた |
| 環境変数 JDK_JAVA_OPTIONS | JDK_JAVA_OPTIONS="--add-opens=java.base/java.util=ALL-UNNAMED" |
動いた(NOTE: Picked up JDK_JAVA_OPTIONS: ... と表示) |
| 実行する JAR の MANIFEST.MF | Add-Opens: java.base/java.util |
java -jar a.jar では動いた |
同じ JAR を java -cp a.jar A で実行 |
(マニフェストは同じ) | 例外のまま |
JAR のマニフェストの Add-Opens は、java -jar で起動したときだけ効きました。 JEP 403 でも、--add-opens とマニフェストの Add-Opens が、特定の package を開ける方法として挙げられています。
テストを別の JVM で動かす設定のときは、java コマンドに付けた --add-opens はテストの JVM には渡りません。テストだけで例外が出るときは、テストの JVM の引数を確かめます。
まず、ライブラリの版を確かめる
このエラーは、自分のコードではなく、ライブラリの中で起きていることがほとんどです。スタックトレースの at の行を下にたどり、どのライブラリが setAccessible を呼んでいるかを探します。
(スタックトレースの形の例)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(...)
at java.base/java.lang.reflect.Field.setAccessible(...)
at com.example.lib.XxxUtil.copy(XxxUtil.java:42) ← ここが原因のライブラリ
JDK 17 に対応した版が出ていれば、そちらに上げるのが根本的な直し方です。--add-opens は、JDK の内部に頼る動きを残すことになるため、ライブラリを上げるまでのつなぎにします。スタックトレースの読み方は、既存の記事「Javaスタックトレースの読み方|Caused byの意味と原因の探し方」で扱っています。
自分のコードなら、例外を出さずに確かめられる
Field f = ArrayList.class.getDeclaredField("elementData");
System.out.println(f.trySetAccessible()); // false(例外にならない)
trySetAccessible() は、使えない場合に例外ではなく false を返しました。 ただし、JDK の内部のフィールドを使わずに、公開されているメソッド(この例なら size() など)で書き直すのが本来の形です。リフレクションの使い方は、既存の記事「Javaリフレクションの使い方|getDeclaredField・invoke」で扱っています。
確認の手順(チェックリスト)
| 順番 | 確認すること | 方法 |
|---|---|---|
| 1 | JDK の版 | java -version(17 以降で例外) |
| 2 | どのライブラリか | スタックトレースの setAccessible の下の行 |
| 3 | ライブラリの新しい版があるか | 依存の版を上げる |
| 4 | すぐ動かすなら | エラー文から --add-opens モジュール/package=ALL-UNNAMED |
| 5 | 起動の方法 | 引数・JDK_JAVA_OPTIONS・java -jar のマニフェスト |
| 6 | テストだけで出るなら | テストの JVM の引数 |
よくある質問
Q. JDK 8 から JDK 17 以降に上げるとき、ほかに出やすいエラーは。
A. class ファイルの版の違いで出る UnsupportedClassVersionError があります。関連記事の「UnsupportedClassVersionErrorの直し方|版の対応表」で扱っています。
まとめ
- リフレクションで JDK の内部を使おうとして、JDK 17 以降で拒否された例外
- JDK 11 の
illegal reflective accessの警告は、17 で止まる予告 - JDK 17 から
--illegal-accessは効かない(JEP 403) - エラー文の
module ○○とopens △△から--add-opens ○○/△△=ALL-UNNAMED - まずライブラリを新しい版に。
--add-opensはつなぎ
参考・出典
確認日はいずれも 2026年10月11日です。
- JEP 403「Strongly Encapsulate JDK Internals」:https://openjdk.org/jeps/403
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「InaccessibleObjectExceptionの直し方|Java 17」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。