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にアクセスすることができますが、将来のバージョンに利用できなくなる可能性があるため、暫定対応としては可能ですが、恒久な方法ではないです。
コメント