Java 9での不正なリフレクトアクセスについては、多くの質問があります。
さて、Googleがすべて吐き出してエラーメッセージを回避しようとしているので私が見つけられないのは、実際には違法なリフレクティブアクセスです。
だから私の質問はかなり簡単です:
不正なリフレクティブアクセスの定義と警告をトリガーする状況
私は、Java 9で導入されたカプセル化の原則と関係があることを収集しましたが、それがすべて一緒にハングアップし、説明が見つからないシナリオで警告をトリガーするものは何ですか。
Java 9での不正なリフレクトアクセスについては、多くの質問があります。
さて、Googleがすべて吐き出してエラーメッセージを回避しようとしているので私が見つけられないのは、実際には違法なリフレクティブアクセスです。
だから私の質問はかなり簡単です:
不正なリフレクティブアクセスの定義と警告をトリガーする状況
私は、Java 9で導入されたカプセル化の原則と関係があることを収集しましたが、それがすべて一緒にハングアップし、説明が見つからないシナリオで警告をトリガーするものは何ですか。
回答:
モジュールとそれらのそれぞれのパッケージ間のアクセスの理解は別として。その核心はモジュールSystem#Relaxed-strong-encapsulationにあると私は信じており、私は質問の関連部分をチェリーピックして質問に答えます。
不正なリフレクティブアクセスの定義と警告をトリガーする状況
Java-9への移行を支援するために、モジュールの強力なカプセル化を緩和できます。
実装は静的アクセスを提供するかもしれません、すなわちコンパイルされたバイトコードによって。
名前のないすべてのモジュールのコード化、つまりクラスパスのコード化に対して開いている1つ以上のモジュールの1つ以上のパッケージでランタイムシステムを呼び出す手段を提供する可能性があります。ランタイムシステムがこの方法で呼び出され、そうすることでリフレクションAPIの一部の呼び出しが成功し、それ以外の場合は失敗します。
そのような場合、純粋なモジュール式の世界ではそのようなアクセスを行うことを意図していないため、実際には「違法」であるリフレクトアクセスを作成することになります。
どのようにすべてがつながっており、どのシナリオで何が警告をトリガーしていますか?
このカプセル化の緩和は、--illegal-accessJava9ではデフォルトで等しい新しいランチャーオプションによって実行時に制御されますpermit。permitモード性を保証
このようなパッケージに対する最初のリフレクトアクセス操作では警告が発行されますが、それ以降は警告は発行されません。この単一の警告は、追加の警告を有効にする方法を説明しています。この警告は抑制できません。
モードは、値debug(メッセージとそのようなアクセスごとのスタックトレース)、warn(そのようなアクセスごとのメッセージ)、およびdeny(そのような操作を無効にする)値で構成できます。
アプリケーションをデバッグして修正することはほとんどありません:-
--illegal-access=denyを回避します。opens--add-opensjdeps、--jdk-internalsオプション付きのツールを使用して識別できます不正な反射アクセス操作が検出されたときに発行される警告メッセージの形式は次のとおりです。
WARNING: Illegal reflective access by $PERPETRATOR to $VICTIM
どこ:
$PERPETRATOR問題のリフレクトオペレーションを呼び出したコードと、コードソース(JARファイルパス)を含む型の完全修飾名(使用可能な場合)、および
$VICTIMアクセスするメンバーを説明する文字列であり、包含タイプの完全修飾名を含みます
このようなサンプル警告の質問:= JDK9:不正なリフレクトアクセス操作が発生しました。org.python.core.PySystemState
最後に重要な注意として、このような警告に直面せず、将来的に安全であることを確認する一方で、モジュールがこれらの不正なリフレクトアクセスを行わないようにする必要があります。:)
Java 9モジュールシステムに関するOracleの記事があります。
デフォルトでは、モジュールの型は、それがパブリック型であり、そのパッケージをエクスポートしない限り、他のモジュールからアクセスできません。公開するパッケージのみを公開します。Java 9では、これはリフレクションにも適用されます。
https://stackoverflow.com/a/50251958/134894で指摘されてAccessibleObject#setAccessibleいるように、JDK8とJDK9の違いは有益です。具体的には、JDK9が追加されました
このメソッドは、クラスCの呼び出し元が次のいずれかが成立する場合にクラスDの宣言のメンバーへのアクセスを有効にするために使用できます。
- CとDは同じモジュールにあります。
- メンバーはパブリックであり、Dは、Dを含むモジュールが少なくともCを含むモジュールにエクスポートするパッケージでパブリックです。
- メンバーは静的に保護され、DはDを含むモジュールが少なくともCを含むモジュールにエクスポートするパッケージでパブリックであり、CはDのサブクラスです。
- Dは、Dを含むモジュールが少なくともCを含むモジュールに対して開くパッケージにあります。名前のないモジュールおよび開いているモジュールのすべてのパッケージは、すべてのモジュールに対して開いているため、Dが名前のないモジュールまたは開いているモジュールにある場合、このメソッドは常に成功します。
モジュールとそのエクスポートの重要性を強調する(Java 9の場合)
–illegal-access=permit...を使用してJVMを起動する
fun
フィールドとメソッドsetAccessible()にアクセスするために使用されるメソッドを見てくださいprivate。
このメソッドが機能するために必要な条件はもっとたくさんあります。それが古いソフトウェアのほとんどすべてを壊さない唯一の理由は、プレーンJARから自動生成されたモジュールが非常に寛容であることです(すべての人のためにすべてを開いてエクスポートします)。