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期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?