【Java】cglibにおけるExceptionInInitializerErrorが発生する際の対策

java
cglibとは

 cglibとは、Javaコード生成ライブラリです。クラスファイルを実行時に読み込んで編集することが可能です。cglibは、HibernateなのDB O/Rマッパーツールや、SpringのAOPコンテナなどで利用されています。

cglibを利用する際の問題点
import net.sf.cglib.proxy.Enhancer;

public class Main {
    public static void main(String[] args) {
        new Enhancer();
    }
}

 java9以上のバージョンで、以上のソースを実行すると、ExceptionInInitializerErrorが発生します。

java.lang.ExceptionInInitializerError
	at main.java.com.avocadosystem.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.instantiate(CglibSubclassingInstantiationStrategy.java:15)
	……
Caused by: net.sf.cglib.core.CodeGenerationException: 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 @2b98378d
	at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:464)
	……
	... 28 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 @2b98378d
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:357)
	……

 

 このエラーの原因は、Java9からモジュール化機能(Module System)が導入されたため、一般的なライブラリでは、JDKパッケージのスキャンとリフレクションが禁止されました。

解決策

 解決策は、外部に公開されていないモジュールを強制的に公開することです。
 以下の2つの方法があります。
 ・Java VM引数に「–add-opens java.base/java.lang=ALL-UNNAMED」を追加すること
 ・Java VM引数に「–illegal-access=permit」を追加すること

 –add-opens コマンドラインオプションは、Add-Opens JARファイルマニフェスト属性とも呼ばれ、特定のパッケージを開くために使用できる。上記の例はすべてのunnamed modulesから java.lang モジュールへのアクセスを許可する意味です。

 –illegal-access コマンドラインオプションは、JEP 261で最初に導入されて、緩和された強力なカプセル化を通じて内部APIにアクセスすることができますが、将来のバージョンに利用できなくなる可能性があるため、暫定対応としては可能ですが、恒久な方法ではないです。

コメント

タイトルとURLをコピーしました