どのようにInaccessibleObjectExceptionを解決するために:Javaの9の上に( "{メンバー}アクセスしやすくすることができません。モジュール{A}を{B}に '{パッケージ}を開き、' しませんか")?

ニコライ:

Javaの9.特定のライブラリやフレームワーク(春、Hibernateは、JAXB)上でアプリケーションを実行するときに、この例外はそれに特に傾向があるさまざまなシナリオで発生します。ここでJavassistのからの例です:

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 @1941a8ff
    at java.base/jdk.internal.reflect.Reflection.throwInaccessibleObjectException(Reflection.java:427)
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:201)
    at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:192)
    at java.base/java.lang.reflect.Method.setAccessible(Method.java:186)
    at javassist.util.proxy.SecurityActions.setAccessible(SecurityActions.java:102)
    at javassist.util.proxy.FactoryHelper.toClass2(FactoryHelper.java:180)
    at javassist.util.proxy.FactoryHelper.toClass(FactoryHelper.java:163)
    at javassist.util.proxy.ProxyFactory.createClass3(ProxyFactory.java:501)
    at javassist.util.proxy.ProxyFactory.createClass2(ProxyFactory.java:486)
    at javassist.util.proxy.ProxyFactory.createClass1(ProxyFactory.java:422)
    at javassist.util.proxy.ProxyFactory.createClass(ProxyFactory.java:394)

メッセージは述べています:

モジュールjava.base:保護された最終のjava.lang.Class java.lang.ClassLoader.defineClass(java.lang.Stringで、バイト[]、int型、int型、すべてjava.security.ProtectionDomainは)ます。java.lang.ClassFormatErrorにアクセススロー作ることができません。無名のモジュールに「java.langのを開き、」しない@ 1941a8ff

何が例外を回避するために行うことができ、プログラムが正常に実行されていますか?

ニコライ:

例外が原因で発生したJavaプラットフォームモジュールシステムのJava 9、強いカプセルの特にその実施に導入されました。それだけで可能にアクセス一定の条件の下では、最も顕著なものは以下のとおりです。

  • タイプは、パブリックである必要があります
  • 所有しているパッケージは、エクスポートする必要があります

同じ制限は、コードが利用しようとした例外を発生させ、反射、についても同様です。より正確には例外がへの呼び出しによって引き起こされますsetAccessibleこれは、上記のスタックトレース、内の対応する行で見ることができjavassist.util.proxy.SecurityActions、以下のような外観。

static void setAccessible(final AccessibleObject ao,
                          final boolean accessible) {
    if (System.getSecurityManager() == null)
        ao.setAccessible(accessible); // <~ Dragons
    else {
        AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                ao.setAccessible(accessible);  // <~ moar Dragons
                return null;
            }
        });
    }
}

必ずプログラムはモジュールシステムがどの要素にアクセスできるように説得しなければなりません正常に実行されるようにするにはsetAccessible呼ばれていましたが。そのために必要なすべての情報は、例外メッセージに含まれているが、ある機構の数、これを達成するためには。どちらがそれを引き起こした正確なシナリオに依存しますが最適です。

モジュール{A}、{B}に{パッケージ}を開き 'ない:{メンバー}アクセスを行うことができません

これまでで最も顕著なシナリオが2以下の通りです:

  1. ライブラリやフレームワークは、JDKのモジュールを呼び出すためにリフレクションを使用しています。このシナリオでは:

    • {A}Javaモジュールは、(接頭辞ですjava.か、jdk.
    • {member}そして、{package}するJava APIの一部であります
    • {B}ライブラリ、フレームワーク、アプリケーションモジュールです。しばしばunnamed module @...
  2. 春、Hibernateは、JAXBのような反射ベースのライブラリ/フレームワークは、...アクセスBean、エンティティにアプリケーションコードの上に反映し、....このシナリオでは:

    • {A} アプリケーションモジュールは、
    • {member}および{package}アプリケーションコードの一部であります
    • {B} いずれかのフレームワークモジュールであるか、または unnamed module @...

いくつかのライブラリ(例えばJAXBは、)あなたがでているもののシナリオをよく見て持っているので、両方のアカウントに失敗することに注意してください!問題の一つはケース1です。

1.反射呼び出しにJDK

私たちは、そのプロパティを変更することはできませんので、JDKのモジュールは、アプリケーション開発者のための不変です。この葉唯一の可能な解決策:コマンドラインフラグ彼らとそれが反射のために開く特定のパッケージに可能です。

したがって、上記のような場合には(短縮)...

java.lang.ClassLoader.defineClassにアクセスできるようにすることができません:モジュールjava.baseは無名のモジュールに「java.langのを開き、」しない@ 1941a8ff

...正しい修正は次のようにJVMを起動することです:

# --add-opens has the following syntax: {A}/{package}={B}
java --add-opens java.base/java.lang=ALL-UNNAMED

反映したコードは名前のモジュール内にある場合は、ALL-UNNAMEDその名前に置き換えることができます。

時々、実際に反射コードを実行するJVMにこのフラグを適用する方法を見つけるのは難しいことができることに留意されたいです。問題のコードは、プロジェクトのビルドプロセスの一部であり、ビルドツールが生まれたことをJVMで実行された場合、これは特に厳しいものになることができます。

あまりにも多くのフラグが追加されるがある場合は、使用して検討するかもしれないカプセル化キルスイッチを --permit-illegal-access代わりに。これは、クラスパス上のすべてのコードは、すべての名前付きのモジュールの上に反映することができます。このフラグがあること注意のみのJava 9で動作します

2.リフレクションを介してアプリケーションコード

このシナリオでは、それはあなたが反射がに侵入するために使用されていることをモジュールを編集できる可能性があります。コマンドラインフラグが必要と代わりのモジュールではないことを意味することに(ない場合は、ケース1には効果的だ){A}の記述は、その内部を開くために使用することができます。さまざまな選択肢があります。

  • パッケージのエクスポートexports {package}すべてのコードにコンパイルし、実行時にそれを利用できるようになり、
  • でアクセスするモジュールにパッケージをエクスポートしexports {package} to {B}、コンパイルし、実行時にだけに、それを利用できるようになり、{B}
  • パッケージ開くopens {package}すべてのコードに(反射の有無にかかわらず)実行時に、それが利用可能になり、
  • アクセスモジュールにパッケージ開くopens {package} to {B}だけに(反射の有無にかかわらず)実行時に、それが利用可能になり、{B}
  • モジュール全体開くopen module {A} { ... }すべてのコードに(反射の有無にかかわらず)実行時に利用可能なすべてのパッケージを作ります、

参照この記事を、より詳細な議論及びこれらのアプローチの比較のために。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

Related 関連記事

ホットタグ

アーカイブ