【エラー解決方法】Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(…) が発生したときの対処法

こんにちは。飯塚です。
 
Javaの環境構築でエラーが発生し、解決までに時間がかかったため、整理のために記事にしました。前半に解決方法をご紹介し、後半に詳細の解説をまとめていきます。

前提となるエラー再現環境

項目 詳細
OS Windows 11
言語 Java 11
IDE Eclipse 2023-12 (4.30.0)
プロジェクト管理ツール Maven

エラーログ:「java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass」

エラーログは下記です。ざっくり言えば、一部のモジュールにアクセスできないため、とあるクラスの読み込みに失敗している、という内容です。

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not “opens java.lang” to unnamed module @7d68ef40

エラー再現プログラム

再現コードです。Persistenceを使用したDB接続の初期準備として行われる処理です。再現には同プロジェクト内に何かしらのEntityクラスも必要ですが、今回は重要ではないので省略しています。

import javax.persistence.Persistence;

public static void main(String[] args) {
		
	Persistence.createEntityManagerFactory("env_local");
		
}

直接原因:ランタイムJREのバージョン誤り

JavaSE-11での実行を想定されたプロジェクトでしたが、ランタイムJREの設定が、JavaSE-21 (jdk-21.0.5) になっていたことが原因でした。Eclipseのバージョンが異なると、デフォルトのJavaのバージョンも異なります。

解決方法:ランタイムJREのバージョンを修正する

jdk-21.0.5 から jdk-11 を選択して実行すると、エラーが解消しました。
 
まずは右クリックします。

「実行」> 「実行の構成」を選択します。

「JRE」タブで正しいバージョンを選択します。あとは「適用」して「実行」します。

原因の詳細:JEP 403: Strongly Encapsulate JDK Internals によって、JDK内部APIへのアクセス制限が強化された

Java17 にバージョンが上がったタイミングで、セキュリティとメンテナンス性向上のため、JDK内部APIへのアクセス制限が強化されていました。
JEP 403: Strongly Encapsulate JDK Internals
 
この変更による影響がそのまま出ていたので、JREのバージョンを変えることで解消しました。

補足:エラーメッセージの内容を読み解く

エラーメッセージの各用語を読み解いて、意味を理解します。

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not “opens java.lang” to unnamed module @7d68ef40

単語 意味
reflect プログラムが実行時に自身の構造を調査し、操作する機能
InaccessibleObjectException Javaのアクセス制限に違反した、という例外
ClassLoader クラスのロードを担当するオブジェクト。クラスのバイナリ名を指定すると、クラス・ローダーはクラスの定義を構成するデータを見つけるか生成する
defineClass バイトの配列をクラスClassのインスタンスに変換するメソッド
java.base Javaプログラミングに不可欠な基本的な機能を提供し、他のすべてのモジュールの基礎となるもの

単語の意味を読み解いて、ざっくりエラーメッセージを意訳すると下記です。

リフレクションを使用して、java.lang.ClassLoaderクラスのdefineClassにアクセスしようとしましたが失敗しました。
 
このメソッドはjava.baseモジュール内のjava.langパッケージに属しており、外部からのアクセスが制限されています。
 
無名モジュール(@7d68ef40)からこのメソッドにアクセスしようとしていますが、java.baseモジュールはjava.langパッケージを「opens」(公開)していないため、アクセスが拒否されています。

Persistence.createEntityManagerFactory()を実行するときに、Hibernateがリフレクションを使用してクラスを読み込むのがエラーのトリガーだったと思われます。

補足:エラーログの全文

少し長いですが、参考程度にエラーログの全文も貼ります。

Exception in thread "main" javax.persistence.PersistenceException: [PersistenceUnit: env_local] Unable to build Hibernate SessionFactory
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:954)
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:884)
	at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:58)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:39)
	at com.codematic.fw.core.commons.db.DBEntityManagerFacroty.createEntityManager(DBEntityManagerFacroty.java:55)
	at com.codematic.fw.core.commons.db.DBManager.createManager(DBManager.java:80)
	at com.codematic.fw.core.commons.db.DBManager.<init>(DBManager.java:39)
	at TestSample.main(TestSample.java:61)
Caused by: org.hibernate.MappingException: Could not get constructor for org.hibernate.persister.entity.SingleTableEntityPersister
	at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:123)
	at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:77)
	at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:344)
	at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:465)
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:881)
	... 7 more
Caused by: org.hibernate.HibernateException: Unable to instantiate default tuplizer [org.hibernate.tuple.entity.PojoEntityTuplizer]
	at org.hibernate.tuple.entity.EntityTuplizerFactory.constructTuplizer(EntityTuplizerFactory.java:91)
	at org.hibernate.tuple.entity.EntityTuplizerFactory.constructDefaultTuplizer(EntityTuplizerFactory.java:116)
	at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:385)
	at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:509)
	at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:124)
	at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486)
	at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:96)
	... 11 more
Caused by: java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:74)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:502)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486)
	at org.hibernate.tuple.entity.EntityTuplizerFactory.constructTuplizer(EntityTuplizerFactory.java:88)
	... 19 more
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @6a370f4
	at java.base/java.lang.reflect.AccessibleObject.throwInaccessibleObjectException(AccessibleObject.java:391)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:367)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:315)
	at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:203)
	at java.base/java.lang.reflect.Method.setAccessible(Method.java:197)
	at javassist.util.proxy.SecurityActions.setAccessible(SecurityActions.java:103)
	at javassist.util.proxy.FactoryHelper.toClass2(FactoryHelper.java:181)
	at javassist.util.proxy.FactoryHelper.toClass(FactoryHelper.java:164)
	at javassist.util.proxy.ProxyFactory.createClass3(ProxyFactory.java:507)
	at javassist.util.proxy.ProxyFactory.createClass2(ProxyFactory.java:492)
	at javassist.util.proxy.ProxyFactory.createClass1(ProxyFactory.java:428)
	at javassist.util.proxy.ProxyFactory.createClass(ProxyFactory.java:400)
	at org.hibernate.proxy.pojo.javassist.JavassistProxyFactory.postInstantiate(JavassistProxyFactory.java:72)
	at org.hibernate.tuple.entity.PojoEntityTuplizer.buildProxyFactory(PojoEntityTuplizer.java:164)
	at org.hibernate.tuple.entity.AbstractEntityTuplizer.<init>(AbstractEntityTuplizer.java:157)
	at org.hibernate.tuple.entity.PojoEntityTuplizer.<init>(PojoEntityTuplizer.java:60)
	at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62)
	... 22 more

参考記事

リフレクションアクセスの原則的な禁止について
JavaAPI仕様ClassLoader.defineClass
Java 20 で java.lang.Void をインスタンス化する

まとめ

いかがでしょうか。
 
バージョンが上がったときの変更点を抑えていなかったのと、リフレクションやClassLoaderのことを詳しく知らなかったため、解決に時間がかかりました。今回のエラーを通して学ぶきっかけができたのは嬉しかったです。
 
 
 
 
《関連記事》

【エラー解決方法】Maven プロジェクト・ビルダー の実行中にエラーが発生
技術
2015.6.18(Thu)

【エラー解決方法】Maven プロジェクト・ビルダー の実行中にエラーが発生

#Java

【エラー解決方法】JRE or JDK must be available in order to run Eclipse を解決する方法
技術
2023.3.24(Fri)

【エラー解決方法】JRE or JDK must be available in order to run Eclipse を解決する方法

#Java#ツール

プログラミング初心者向け!エラーメッセージの読み方をサンプル付きで解説
技術
2024.5.24(Fri)

プログラミング初心者向け!エラーメッセージの読み方をサンプル付きで解説

#まとめ#技術

記事をシェア
MOST VIEWED ARTICLES