Movatterモバイル変換


[0]ホーム

URL:


PDF, PPTX2,460 views

JDK 16 で導入された JEP 396 にご注意!! (JJUG CCC 2021 Spring)

JJUG CCC 2021 Spring にて講演。2021年3月リリースのJDK 16 では、17個の JEP(JDK Enhancement Proposal)が導入されました。 JDK 16で導入された JEP 396: Strongly Encapsulate JDK Internals by Default による影響は十分に評価・準備することをお勧めします。 今回は、JEP 396での変更点やその背景を解説すると共に、アプリケーションでの評価・確認する際のポイントをご紹介します。

Embed presentation

Download as PDF, PPTX
JDK 16で導入されたJEP 396にご注意!!JEP 396 : Strongly Encapsulate JDK Internals by DefaultJJUG CCC 2021 Spring2021年5月23日徳益芳郎
Yoshiro TokumasuSoftware Engineerhttps://www.slideshare.net/tokumasu123/presentations使ってみよう!JDK Flight Recorder2018年12月11日徳益 芳郎Duke 出典:An Oracle blog about Oracle Enterprise Pack for Eclipse「Java 8 Launch!」ログ出力を改めて考える- JDK Flight Recorder の活用 -2019年6月27日徳益 芳郎Duke 出典:An Oracle blog about Oracle Enterprise Pack for Eclipse「Java 8 Launch!」
はじめに2021年3月リリースのJDK 16では、17個の JEP(JDK Enhancement Proposal)が導入されました。導入された JEP に関する個々の詳細は、OpenJDK サイトの JDK 16 をご覧ください。JDK 16 で導入された JEP のうち、JEP 396 : Strongly Encapsulate JDKInternals by Default による影響は十分に評価・準備することをお勧めします。本セッションでは、JEP 396での変更点やその背景を解説すると共に、アプリケーションでの評価・確認する際のポイントをご紹介します。3
JEP 396 :Strongly Encapsulate JDK Internals by Default
このような警告メッセージを見たことありませんか?WARNING: An illegal reflective access operation has occurredWARNING: Illegal reflective access by org.jruby.ext.openssl.SecurityHelper (file:/tmp/jruby-1/jruby5029500797019692358jopenssl.jar) to field java.security.MessageDigest.providerWARNING: Please consider reporting this to the maintainers oforg.jruby.ext.openssl.SecurityHelperWARNING: Use --illegal-access=warn to enable warnings of further illegal reflective accessoperationsWARNING: All illegal access operations will be denied in a future release5
JEP 396での変更点従来(JDK 9 ∼ 15)--illegal-access=permit をデフォルト設定としてJava VMが起動する今後(JDK 16以降)--illegal-access=deny をデフォルト設定としてJava VMが起動する6
JEP 396による影響モジュール化していないアプリケーションやライブラリ(OSSを含む)にて、sun.* や com.sun.* パッケージを含むJDK内部APIを利用している場合、アプリケーション実行時に InaccessibleObjectException などのランタイム例外が発生する7
JEP 396の背景JDK 9リリース時に導入されたモジュール化ですが、完全なカプセル化を強制すると影響が大きいということで、妥協した状態(--illegal-access=permit:Relaxed strong encapsulation)で導入され、JDK内部APIを利用しない実装へ改修するための移行期間を設けていたしかし次のLTS(Long Term Support)候補であるJDK 17のリリース(2021年9月予定)が見えてきた今(JDK 16 リリース時)、次の段階(--illegal-access=deny:Strong encapsulation)に進むことになる8
モジュールに対するアクセス制御モジュールシステムの基本
モジュール化従来のJARファイルmodule foo {exports bar;opens fizz;requires buzz;}モジュール定義module-infoモジュラJARファイル10
アクセス制御はモジュール定義に従うmodule-infomodule-infoDirectReflectionDeep
Reflectionmodule bar {exports a;}module-infomodule fizz {exports c;opens c;}module foo {requires bar;requires buzz;}module-infomodule buzz {exports b;opens b;}<凡例>  :モジュール定義に従いアクセスできない(例外発生) 11foo barfizzbuzz
モジュールの分類モジュールシステムにおける経過措置
モジュール対応状況と配備場所Unnamed Modules--class-path --module-path従来のJARファイル 従来のJARファイルmodule-infoモジュラJARファイルmodule-infoモジュラJARファイルmodule-infoAutomatic ModulesNamed Modules無視生成13JARファイル名 モジュール名module-info生成モジュール名がない!module-info生成モジュール名がない!
Unnamed / Automatic Modulesの扱いモジュール定義 Unnamed Modules Automatic Modulesname なしJarファイル名 または、JarファイルのMANIFEST属性で指定requiresALL-MODULE-PATHALL-UNNAMEDALL-SYSTEMALL-MODULE-PATHALL-UNNAMEDALL-SYSTEMexports *(全て公開) *(全て公開)opens *(全て許可) *(全て許可)14
モジュールの分類System ModulesUnnamed Modules Automatic ModulesNamed Modulesmodule-infofizzmodule-infomodule-info15module-info⁉モジュール名がない!経過措置:将来は削除される予定だが、JDK 16 でも継続されるJARファイル名 モジュール名
モジュール分類間のアクセス制御Illegal-access が発生する箇所(モジュール分類間)を知る!
モジュールの分類System ModulesUnnamed Modules Automatic ModulesNamed Modulesmodule-infofizzmodule-infomodule-info17module-info⁉モジュール名がない! JARファイル名 モジュール名再掲載
module-infoAutomatic ModulesUnnamed Modules → Automatic ModulesUnnamed Modules18⁉module-infoモジュール名がない!Unnamed Modules は、Automatic Modules を含む全てのモジュールを参照(requires)と定義されているJARファイル名 モジュール名module fileA {exports *;opens *;}全てのパッケージを公開全てのパッケージへの Deep Reflection を許可<凡例>   :モジュール定義に従いアクセス制御されるDirectReflectionDeep
Reflection
module-infoAutomatic ModulesAutomatic Modules → Unnamed ModulesUnnamed Modules19DirectReflectionDeep
Reflectionmodule ⁉ {exports *;opens *;}全てのパッケージを公開全てのパッケージへの Deep Reflection を許可⁉module-infoAutomatic Modules は、Unnamed Modules を含む全てのモジュールを参照(requires)と定義されているモジュール名がない! JARファイル名 モジュール名<凡例>   :モジュール定義に従いアクセス制御される
Unnamed Modules → Named Modules⁉module-infoモジュール名がない!fizzmodule-infoNamed ModulesUnnamed Modules は、Named Modules を含む全てのモジュールを参照(requires)と定義されている<凡例>   :モジュール定義に従いアクセス制御されるDirectReflectionDeep
Reflectionmodule fizz {exports D;opens D;}モジュール定義の内容は、モジュール毎に異なるUnnamed Modules20
module-infoAutomatic ModulesAutomatic Modules → Named Modules21JARファイル名 モジュール名<凡例>   :モジュール定義に従いアクセス制御されるfizzmodule-infoNamed ModulesDirectReflectionDeep
ReflectionAutomatic Modules は、Named Modules を含む全てのモジュールを参照(requires)と定義されているmodule fizz {exports D;opens D;}モジュール定義の内容は、モジュール毎に異なる
Named Modules → Unnamed ModulesUnnamed Modulesfizzmodule-infoNamed Modules22DirectReflectionDeep
Reflection⁉<凡例>  :Named Modules のモジュール定義にて requires 指定できないので、アクセスできないmodule ⁉ {exports *;opens *;}Unnamed Modules は、モジュール名がないmodule-infoモジュール名がない!Named Modules は、参照したいモジュールをrequires で定義する必要がある
module-infoAutomatic ModulesNamed Modules → Automatic Modules23JARファイル名 モジュール名<凡例>   :モジュール定義に従いアクセス制御されるfizzmodule-infoNamed Modulesmodule fizz {exports D;opens D;requires fileA;}Named Modules は、参照したいモジュールをrequires で定義する必要があるmodule fileA {exports *;opens *;}全てのパッケージを公開全てのパッケージへの Deep Reflection を許可DirectReflectionDeep
Reflection
module-infoAutomatic ModulesAutomatic Modules → System Modules24DirectReflectionDeep
ReflectionAutomatic Modules は、System Modules を含む全てのモジュールを参照(requires)と定義されているJARファイル名 モジュール名System Modulesmodule-infomodule buzz {exports D;}モジュール定義の内容は、モジュール毎に異なる<凡例>   :モジュール定義に従いアクセス制御される
Unnamed Modules → System Modules25System Modulesmodule-infoUnnamed Modules⁉module-infoモジュール名がない!module buzz {exports D;}Unnamed Modules は、System Modules を含む全てのモジュールを参照(requires)と定義されているDirectReflectionDeep
Reflection!--illegal-access=permitJDK 15 以前の挙動! !<凡例>   :モジュール定義に反して常にアクセス可能(警告メッセージ)!
モジュール定義に反して常にアクセス可能$ java --show-version Main2.javaopenjdk 15.0.2 2021-01-19OpenJDK Runtime Environment (build 15.0.2+7-27)OpenJDK 64-Bit Server VM (build 15.0.2+7-27, mixed mode, sharing)WARNING: An illegal reflective access operation has occurredWARNING: Illegal reflective access by Main2 (file:/2021/Main2.java) to methodjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean)WARNING: Please consider reporting this to the maintainers of Main2WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operationsWARNING: All illegal access operations will be denied in a future release26
Unnamed Modules → System Modules27System Modulesmodule-infoUnnamed Modules⁉module-infoモジュール名がない!module buzz {exports D;}モジュール定義の内容は、モジュール毎に異なるUnnamed Modules は、System Modules を含む全てのモジュールを参照(requires)と定義されているDirectReflectionDeep
Reflection--illegal-access=denyJDK 16 以降の挙動<凡例>   :モジュール定義に従いアクセス制御される
モジュール定義に従いアクセス制御される$ java --show-version Main2.javaopenjdk 16 2021-03-16OpenJDK Runtime Environment (build 16+35-2229)OpenJDK 64-Bit Server VM (build 16+35-2229, mixed mode, sharing)java.lang.reflect.InaccessibleObjectException: Unable to make private booleanjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean) accessible: module java.basedoes not "opens java.util.concurrent" to unnamed module @7f416310at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:357)at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)at Main3.main(Main2.java:18)28RuntimeException
JDK内部APISystem Modules の非公開な APIのうち、--illegal-access=deny の影響を受ける箇所(分類)を知る!
JDK内部API本来、アプリケーションやライブラリで利用されることを想定していない非公開な API であり、sun.* や com.sun.* または jdk.* パッケージなど…ここでは、以下の3つに分類する代替APIが存在する影響が大きいその他30System Modulesmodule-info
代替APIが存在する JDK内部APIhttps://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+Tool 31JDK 8の時点で既に代替APIが提供されており、現在は削除されている標準APIJDK内部API標準APIJDK内部API
影響が大きい JDK内部API重要な機能を提供しているが、現時点でも代替APIが存在しない…経過措置:jdk.unsupported モジュールに格納されて提供されている将来は削除される予定だが、JDK 16 でも継続されるsun.misc.Signalsun.misc.SignalHandlersun.misc.Unsafesun.reflect.Reflection::getCallerClass(int)sun.reflect.ReflectionFactorycom.sun.nio.file.ExtendedCopyOptioncom.sun.nio.file.ExtendedOpenOptioncom.sun.nio.file.ExtendedWatchEventModifiercom.sun.nio.file.SensitivityWatchEventModifier$ java --describe-module jdk.unsupportedjdk.unsupported@16exports com.sun.nio.fileexports sun.miscexports sun.reflectrequires java.base mandatedopens sun.miscopens sun.reflectJDK 9 で代替APIが提供されたのでJDK 11で削除された32
その他 JDK内部API① 他の分類に該当しない、sun.* や com.sun.* パッケージなどの非公開パッケージJDK 9以降の環境では、基本的にカプセル化されている(アクセス不可)経過措置(JDK15まで):実行時に限り、Unnamed module に対して公開 (exports)② 全パッケージに含まれる private クラスやメソッド、フィールドなど…Deep Reflection によるアクセスを必須とする経過措置(JDK15まで):Unnamed module に対して deep reflection を許可 (opens)33
JDK内部APIの分類とその影響JEP 396(--illegal-access のパラメータを permit から deny に変更)の影響がJDK内部APIの分類に応じて異なるJDK内部APIの分類 --illegal-access=permit --illegal-access=deny代替APIが存在する ❌(NoClassDefFoundError などが発生)❌(NoClassDefFoundError などが発生)影響が大きい(jdk.unsupported モジュール)✔ ✔その他 ✔ ❌(InaccessibleObjectException などが発生)<凡例> ✔:問題なくアクセス可能 ❌:アクセス不可(例外が発生する)34JDK 16 のデフォルト値
--illegal-access=<parameter>Java VM 起動オプション
Unnamed Module による許可されていないJDK内部APIへのアクセスに対する挙動を、パラメータ値に応じて制御する--illegal-access のパラメータと挙動パラメータ値 初回アクセス 2回目以降のアクセス 補足permit △ ✔ JDK 9 ∼15のデフォルト値warn △ △ ーdebug△(スタックトレースも出力)△(スタックトレースも出力)ーdeny ❌ ❌ JDK 16以降のデフォルト値<凡例> ✔:問題なくアクセス可能 △:アクセス可能(但し、警告メッセージを出力) ❌:アクセス不可(例外が発生する)36
--illegal-access=warn の場合$ java --show-version --illegal-access=warn Main2.javaopenjdk 15.0.2 2021-01-19OpenJDK Runtime Environment (build 15.0.2+7-27)OpenJDK 64-Bit Server VM (build 15.0.2+7-27, mixed mode, sharing)WARNING: Illegal reflective access by Main2 (file:/2021/Main2.java) to methodjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean)WARNING: Illegal reflective access by Main2 (file:/2021/Main2.java) to methodjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean)WARNING: Illegal reflective access by Main2 (file:/2021/Main2.java) to fieldcom.sun.crypto.provider.BlowfishConstants.BLOWFISH_BLOCK_SIZE37警告メッセージ(許可されないアクセスの回数分)
--illegal-access=debug の場合$ java --show-version --illegal-access=debug Main2.javaopenjdk 15.0.2 2021-01-19OpenJDK Runtime Environment (build 15.0.2+7-27)OpenJDK 64-Bit Server VM (build 15.0.2+7-27, mixed mode, sharing)WARNING: Illegal reflective access by Main2 (file:/2021/Main2.java) to methodjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean)at Main2.main(Main2.java:18)WARNING: Illegal reflective access by Main2 (file:/2021/Main2.java) to methodjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean)at Main2.main(Main2.java:26)WARNING: Illegal reflective access by Main2 (file:/2021/Main2.java) to fieldcom.sun.crypto.provider.BlowfishConstants.BLOWFISH_BLOCK_SIZEat Main2.main(Main2.java:35)38警告メッセージとスタックトーレス(許可されないアクセスの回数分)
影響ある箇所の特定方法は⁉その他 に分類されるJDK内部APIを利用する箇所を特定する
JDK内部APIの分類とその影響JEP 396(--illegal-access のパラメータを permit から deny に変更)の影響がJDK内部APIの分類に応じて異なるJDK内部APIの分類 --illegal-access=permit --illegal-access=deny代替APIが存在する ❌(NoClassDefFoundError などが発生)❌(NoClassDefFoundError などが発生)影響が大きい(jdk.unsupported モジュール)✔ ✔その他 ✔ ❌(InaccessibleObjectException などが発生)<凡例> ✔:問題なくアクセス可能 ❌:アクセス不可(例外が発生する)40JDK 16 のデフォルト値再掲載
JDK内部APIを利用するコード例try {sun.misc.BASE64Encoder b64 = new sun.misc.BASE64Encoder();System.out.println(b64.encode(new byte[]{1, 2, 3}));} catch (Throwable ex) { ex.printStackTrace(); }try {Field field = sun.misc.Unsafe.class.getDeclaredField(“theUnsafe");field.setAccessible(true);sun.misc.Unsafe unsafe = (sun.misc.Unsafe) field.get(null);} catch (Exception ex) { ex.printStackTrace(); }try {java.util.conccurent.ThreadPoolExecutor executor =new ThreadPoolExecutor(5, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());Method addWorker = ThreadPoolExecutor.class.getDeclaredMethod(“addWorker", Runnable.class, Boolean.TYPE);addWorker.setAccessible(true);addWorker.invoke(executor, null, Boolean.FALSE);} catch (Exception ex) { ex.printStackTrace(); }その他41Deep Reflection代替APIが存在する影響が大きい
jdeps ツールで確認⁉$ jdeps --jdk-internals --class-path test.legacy.main.jartest.legacy.main.jar -> jdk8internalstest.legacy.main.jar -> jdk.unsupportedtest.main.Main -> sun.misc.BASE64Encoder JDK internal API (jdk8internals)test.main.Main -> sun.misc.Unsafe JDK internal API (jdk.unsupported)警告: JDK内部APIはサポートされておらず、JDK実装専用ですが、互換性なしで削除または変更される場合があり、アプリケーションを中断させる可能性があります。JDK内部APIの依存性を削除するようコードを変更してください。JDK内部APIの置換に関する最新の更新については、次を確認してください:https://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+ToolJDK内部API 修正候補-------- ----sun.misc.BASE64Encoder Use java.util.Base64 @since 1.8sun.misc.Unsafe See http://openjdk.java.net/jeps/26042
jdeps ツールで確認する際の注意点--jdk-internals オプションで確認できる JDK内部API の種類は限られる!JDK内部APIの分類 jdepsツールでの確認 例代替APIが存在する ✔ sun.misc.BASE64Decodersun.reflect.Reflection.getCallerClass影響が大きい(jdk.unsupported モジュール)✔ sun.misc.Unsafecom.sun.nio.file.ExtendedCopyOptionその他 ❌java.util.concurrent.ThreadPoolExecutor.addWorkerjava.security.MessageDigest.providersun.security.util.SecurityConstants<凡例> ✔:確認できる ❌:確認できない43direct アクセスの箇所のみ検出できる
⁉setAccessible(true) の箇所を特定⁉全てのソースコード(商用版を含む)を保持しているなら可能かもねぇ…OSSの場合でもマイナーバージョンまで完全把握していないとねぇ…System modules 以外のモジュールに対する箇所もヒットするけどねぇ…やらないより、やる価値はあるので、自作のソースコードだけでも!44
JDK 16 以降に向けた準備・確認以下のように JEP 396 による影響を確認する1.--illegal-access=debug を明示的に指定して Java VM を起動する警告メッセージとスタックトレースを基に修正すべき箇所を確認する2.--illegal-access=deny を明示的に指定して Java VM を起動する例外が発生することなく、アプリケーションが正常動作することを確認する45
JDK 16 で実行してみた…
JDK 16 では、やっぱり例外発生!$ java --show-version Main3.javaopenjdk 16 2021-03-16OpenJDK Runtime Environment (build 16+35-2229)OpenJDK 64-Bit Server VM (build 16+35-2229, mixed mode, sharing)java.lang.reflect.InaccessibleObjectException: Unable to make private booleanjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean) accessible: module java.basedoes not "opens java.util.concurrent" to unnamed module @7f416310at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:357)at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)at Main3.main(Main3.java:18)47RuntimeException
ソースコード修正なしに対処するには…$ java --show-version --add-opens java.base/java.util.concurrent=ALL-UNNAMED Main3.javaopenjdk 16 2021-03-16OpenJDK Runtime Environment (build 16+35-2229)OpenJDK 64-Bit Server VM (build 16+35-2229, mixed mode, sharing)48この対処は、リスクをともなうので注意が必要であるモジュール提供者の意思に反している!JDK内部APIが変更・削除された場合、失敗する!
JDK 16 では --illegal-access は deprecated$ java --show-version --illegal-access=permit Main3.javaOpenJDK 64-Bit Server VM warning: Option --illegal-access is deprecated and will be removed in a future release.openjdk 16 2021-03-16OpenJDK Runtime Environment (build 16+35-2229)OpenJDK 64-Bit Server VM (build 16+35-2229, mixed mode, sharing)WARNING: An illegal reflective access operation has occurredWARNING: Illegal reflective access by Main3 (file:/2021/Main3.java) to methodjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean)WARNING: Please consider reporting this to the maintainers of Main3WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operationsWARNING: All illegal access operations will be denied in a future release49警告メッセージ(初回アクセス分のみ)
まとめ
JEP 396での変更点従来(JDK 9 ∼ 15)--illegal-access=permit をデフォルト設定としてJava VMが起動する今後(JDK 16以降)--illegal-access=deny をデフォルト設定としてJava VMが起動する51再掲載
Unnamed Modules → System Modules52System Modulesmodule-infoUnnamed Modules⁉module-infoモジュール名がない!module buzz {exports D;}モジュール定義の内容は、モジュール毎に異なるUnnamed Modules は、System Modules を含む全てのモジュールを参照(requires)と定義されているDirectReflectionDeep
Reflection--illegal-access=permitJDK 15 以前の挙動 再掲載! !<凡例>   :モジュール定義に反して常にアクセス可能(警告メッセージ)!!
Unnamed Modules → System Modules53System Modulesmodule-infoUnnamed Modules⁉module-infoモジュール名がない!module buzz {exports D;}モジュール定義の内容は、モジュール毎に異なるUnnamed Modules は、System Modules を含む全てのモジュールを参照(requires)と定義されているDirectReflectionDeep
Reflection--illegal-access=denyJDK 16 以降の挙動<凡例>   :モジュール定義に従いアクセス制御される再掲載
その他 JDK内部API① 他の分類に該当しない、sun.* や com.sun.* パッケージなどの非公開パッケージJDK 9以降の環境では、基本的にカプセル化されている(アクセス不可)経過措置(JDK15まで):実行時に限り、Unnamed module に対して公開 (exports)② 全パッケージに含まれる private クラスやメソッド、フィールドなど…Deep Reflection によるアクセスを必須とする経過措置(JDK15まで):Unnamed module に対して deep reflection を許可 (opens)54再掲載
JDK 16 以降に向けた準備・確認以下のように JEP 396 による影響を確認する1.--illegal-access=debug を明示的に指定して Java VM を起動する警告メッセージとスタックトレースを基に対処すべき箇所を確認する2.--illegal-access=deny を明示的に指定して Java VM を起動する例外が発生することなく、アプリケーションが正常動作することを確認する55再掲載
--add-opens/--add-exports のリスク$ java --show-version --add-opens java.base/java.util.concurrent=ALL-UNNAMED Main2.javaopenjdk 16 2021-03-16OpenJDK Runtime Environment (build 16+35-2229)OpenJDK 64-Bit Server VM (build 16+35-2229, mixed mode, sharing)56この対処は、リスクをともなうので注意が必要であるモジュール提供者の意思に反している!JDK内部APIが変更・削除された場合、失敗する!
APPENDIX
参考情報JDK 16 - OpenJDK -https://openjdk.java.net/projects/jdk/16/JEP 396: Strongly Encapsulate JDK Internals by Defaulthttps://openjdk.java.net/jeps/396Relaxed Strong encapsulation - JEP 261: Module System -https://openjdk.java.net/jeps/261#Relaxed-strong-encapsulation58
参考情報JEP 260: Encapsulate Most Internal APIshttps://openjdk.java.net/jeps/260Replace uses of the JDK’s internal APIs - Java Dependency Analysis Tool -https://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+ToolInternal packages that will no longer be open by default 
/ Exported packages that will no longer be open by defaulthttps://cr.openjdk.java.net/~mr/jigsaw/jdk8-packages-denied-by-default59
その他使ってみよう!JDK Flight Recorderhttps://www.slideshare.net/tokumasu123/jdk-flight-recorder-126001298ログ出力を改めて考える - JDK Flight Recorder の活用 -https://www.slideshare.net/tokumasu123/jdk-flight-recorder-155345312JFR Event Streaming によるAP監視 - JDK Flight Recorder の活用 -https://www.slideshare.net/tokumasu123/jfr-event-streamingap-jdk-flight-recorder60
END“JDK 16 で導入された JEP 396 にご注意”JEP 396 : Strongly Encapsulate JDK Internals by Default
JDK 16 で導入された JEP 396 にご注意!! (JJUG CCC 2021 Spring)

Recommended

PDF
最適なOpenJDKディストリビューションの選び方 #codetokyo19B3 #ccc_l5
PDF
これからのJDK 何を選ぶ?どう選ぶ? (v1.2) in 熊本
PPTX
Metaspace
PPTX
Java 17直前!オレ流OpenJDK「の」開発環境(Open Source Conference 2021 Online/Kyoto 発表資料)
PDF
Garbage First Garbage Collection (G1 GC) #jjug_ccc #ccc_cd6
PDF
Unified JVM Logging
PDF
雑なMySQLパフォーマンスチューニング
PDF
PostgreSQLをKubernetes上で活用するためのOperator紹介!(Cloud Native Database Meetup #3 発表資料)
PDF
これからのJDK/JVM 何を選ぶ?どう選ぶ?
PPTX
分散トレーシングAWS:X-Rayとの上手い付き合い方
PDF
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
PDF
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
PDF
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
PDF
YugabyteDBを使ってみよう - part2 -(NewSQL/分散SQLデータベースよろず勉強会 #2 発表資料)
PDF
Java仮想マシンの実装技術
PDF
Serverless時代のJavaについて
PDF
シンプルでシステマチックな Linux 性能分析方法
PDF
例外設計における大罪
PDF
トランザクション処理可能な分散DB 「YugabyteDB」入門(Open Source Conference 2022 Online/Fukuoka 発...
PDF
Java によるクラウドネイティブ の実現に向けて
PPTX
さくっと理解するSpring bootの仕組み
PDF
JVMのGCアルゴリズムとチューニング
PDF
株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...
PPTX
GraalVMのJavaネイティブビルド機能でどの程度起動が速くなるのか?~サーバレス基盤上での評価~ / How fast does GraalVM's...
PPTX
Spanner移行について本気出して考えてみた
PPTX
GitLab から GitLab に移行したときの思い出
PDF
PostgreSQLでスケールアウト
PDF
怖くないSpring Bootのオートコンフィグレーション
PPTX
Java 18で入ったJVM関連の(やや細かめな)改善(JJUGナイトセミナー「Java 18 リリース記念イベント」発表資料)
PDF
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)

More Related Content

PDF
最適なOpenJDKディストリビューションの選び方 #codetokyo19B3 #ccc_l5
PDF
これからのJDK 何を選ぶ?どう選ぶ? (v1.2) in 熊本
PPTX
Metaspace
PPTX
Java 17直前!オレ流OpenJDK「の」開発環境(Open Source Conference 2021 Online/Kyoto 発表資料)
PDF
Garbage First Garbage Collection (G1 GC) #jjug_ccc #ccc_cd6
PDF
Unified JVM Logging
PDF
雑なMySQLパフォーマンスチューニング
PDF
PostgreSQLをKubernetes上で活用するためのOperator紹介!(Cloud Native Database Meetup #3 発表資料)
最適なOpenJDKディストリビューションの選び方 #codetokyo19B3 #ccc_l5
これからのJDK 何を選ぶ?どう選ぶ? (v1.2) in 熊本
Metaspace
Java 17直前!オレ流OpenJDK「の」開発環境(Open Source Conference 2021 Online/Kyoto 発表資料)
Garbage First Garbage Collection (G1 GC) #jjug_ccc #ccc_cd6
Unified JVM Logging
雑なMySQLパフォーマンスチューニング
PostgreSQLをKubernetes上で活用するためのOperator紹介!(Cloud Native Database Meetup #3 発表資料)

What's hot

PDF
これからのJDK/JVM 何を選ぶ?どう選ぶ?
PPTX
分散トレーシングAWS:X-Rayとの上手い付き合い方
PDF
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
PDF
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
PDF
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
PDF
YugabyteDBを使ってみよう - part2 -(NewSQL/分散SQLデータベースよろず勉強会 #2 発表資料)
PDF
Java仮想マシンの実装技術
PDF
Serverless時代のJavaについて
PDF
シンプルでシステマチックな Linux 性能分析方法
PDF
例外設計における大罪
PDF
トランザクション処理可能な分散DB 「YugabyteDB」入門(Open Source Conference 2022 Online/Fukuoka 発...
PDF
Java によるクラウドネイティブ の実現に向けて
PPTX
さくっと理解するSpring bootの仕組み
PDF
JVMのGCアルゴリズムとチューニング
PDF
株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...
PPTX
GraalVMのJavaネイティブビルド機能でどの程度起動が速くなるのか?~サーバレス基盤上での評価~ / How fast does GraalVM's...
PPTX
Spanner移行について本気出して考えてみた
PPTX
GitLab から GitLab に移行したときの思い出
PDF
PostgreSQLでスケールアウト
PDF
怖くないSpring Bootのオートコンフィグレーション
これからのJDK/JVM 何を選ぶ?どう選ぶ?
分散トレーシングAWS:X-Rayとの上手い付き合い方
バイトコードって言葉をよく目にするけど一体何なんだろう?(JJUG CCC 2022 Spring 発表資料)
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
Javaコードが速く実⾏される秘密 - JITコンパイラ⼊⾨(JJUG CCC 2020 Fall講演資料)
YugabyteDBを使ってみよう - part2 -(NewSQL/分散SQLデータベースよろず勉強会 #2 発表資料)
Java仮想マシンの実装技術
Serverless時代のJavaについて
シンプルでシステマチックな Linux 性能分析方法
例外設計における大罪
トランザクション処理可能な分散DB 「YugabyteDB」入門(Open Source Conference 2022 Online/Fukuoka 発...
Java によるクラウドネイティブ の実現に向けて
さくっと理解するSpring bootの仕組み
JVMのGCアルゴリズムとチューニング
株式会社コロプラ『GKE と Cloud Spanner が躍動するドラゴンクエストウォーク』第 9 回 Google Cloud INSIDE Game...
GraalVMのJavaネイティブビルド機能でどの程度起動が速くなるのか?~サーバレス基盤上での評価~ / How fast does GraalVM's...
Spanner移行について本気出して考えてみた
GitLab から GitLab に移行したときの思い出
PostgreSQLでスケールアウト
怖くないSpring Bootのオートコンフィグレーション

Similar to JDK 16 で導入された JEP 396 にご注意!! (JJUG CCC 2021 Spring)

PPTX
Java 18で入ったJVM関連の(やや細かめな)改善(JJUGナイトセミナー「Java 18 リリース記念イベント」発表資料)
PDF
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
PDF
ClassLoader Leak Patterns
 
PPTX
Jdk9で変更になる(かも知れない)jvmオプションの標準設定
PDF
10のJava9で変わるJava8の嫌なとこ!
PDF
Javaヂカラ #Java最新動向 -Java 11 の新機能やOracle Code One 2018 発の最新技術トレンドを一気にキャッチアップ-
PPTX
Let's Start Contributing to OpenJDK from Today!(Oracle Groundbreakers APAC Vi...
PDF
Prepare for Java 9 #jjug
PDF
JavaOne 2016 Java SE Feedback #jjug #j1jp
PPTX
Cve 2013-0422
ODP
これから Haskell を書くにあたって
PDF
今年はJava進化の年!今知っておくべき新しいJava
PDF
Head toward Java 16 (Night Seminar Edition)
PPT
Java 7
PDF
JavaOne 2015 JDK Update (Jigsaw) #j1jp
PDF
JDK Mission Control: Where We Are, Where We Are Going [Groundbreakers APAC 20...
PDF
Valhalla Update JJUG CCC Spring 2019
PDF
Var handles jjug_ccc_spring_2018
KEY
関ジャバ JavaOne Tokyo 2012報告会
PDF
Head toward Java 15 and Java 16
Java 18で入ったJVM関連の(やや細かめな)改善(JJUGナイトセミナー「Java 18 リリース記念イベント」発表資料)
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
ClassLoader Leak Patterns
 
Jdk9で変更になる(かも知れない)jvmオプションの標準設定
10のJava9で変わるJava8の嫌なとこ!
Javaヂカラ #Java最新動向 -Java 11 の新機能やOracle Code One 2018 発の最新技術トレンドを一気にキャッチアップ-
Let's Start Contributing to OpenJDK from Today!(Oracle Groundbreakers APAC Vi...
Prepare for Java 9 #jjug
JavaOne 2016 Java SE Feedback #jjug #j1jp
Cve 2013-0422
これから Haskell を書くにあたって
今年はJava進化の年!今知っておくべき新しいJava
Head toward Java 16 (Night Seminar Edition)
Java 7
JavaOne 2015 JDK Update (Jigsaw) #j1jp
JDK Mission Control: Where We Are, Where We Are Going [Groundbreakers APAC 20...
Valhalla Update JJUG CCC Spring 2019
Var handles jjug_ccc_spring_2018
関ジャバ JavaOne Tokyo 2012報告会
Head toward Java 15 and Java 16

JDK 16 で導入された JEP 396 にご注意!! (JJUG CCC 2021 Spring)

  • 1.
    JDK 16で導入されたJEP 396にご注意!!JEP396 : Strongly Encapsulate JDK Internals by DefaultJJUG CCC 2021 Spring2021年5月23日徳益芳郎
  • 2.
    Yoshiro TokumasuSoftware Engineerhttps://www.slideshare.net/tokumasu123/presentations使ってみよう!JDKFlight Recorder2018年12月11日徳益 芳郎Duke 出典:An Oracle blog about Oracle Enterprise Pack for Eclipse「Java 8 Launch!」ログ出力を改めて考える- JDK Flight Recorder の活用 -2019年6月27日徳益 芳郎Duke 出典:An Oracle blog about Oracle Enterprise Pack for Eclipse「Java 8 Launch!」
  • 3.
    はじめに2021年3月リリースのJDK 16では、17個の JEP(JDKEnhancement Proposal)が導入されました。導入された JEP に関する個々の詳細は、OpenJDK サイトの JDK 16 をご覧ください。JDK 16 で導入された JEP のうち、JEP 396 : Strongly Encapsulate JDKInternals by Default による影響は十分に評価・準備することをお勧めします。本セッションでは、JEP 396での変更点やその背景を解説すると共に、アプリケーションでの評価・確認する際のポイントをご紹介します。3
  • 4.
    JEP 396 :StronglyEncapsulate JDK Internals by Default
  • 5.
    このような警告メッセージを見たことありませんか?WARNING: An illegalreflective access operation has occurredWARNING: Illegal reflective access by org.jruby.ext.openssl.SecurityHelper (file:/tmp/jruby-1/jruby5029500797019692358jopenssl.jar) to field java.security.MessageDigest.providerWARNING: Please consider reporting this to the maintainers oforg.jruby.ext.openssl.SecurityHelperWARNING: Use --illegal-access=warn to enable warnings of further illegal reflective accessoperationsWARNING: All illegal access operations will be denied in a future release5
  • 6.
    JEP 396での変更点従来(JDK 9∼ 15)--illegal-access=permit をデフォルト設定としてJava VMが起動する今後(JDK 16以降)--illegal-access=deny をデフォルト設定としてJava VMが起動する6
  • 7.
    JEP 396による影響モジュール化していないアプリケーションやライブラリ(OSSを含む)にて、sun.* やcom.sun.* パッケージを含むJDK内部APIを利用している場合、アプリケーション実行時に InaccessibleObjectException などのランタイム例外が発生する7
  • 8.
    JEP 396の背景JDK 9リリース時に導入されたモジュール化ですが、完全なカプセル化を強制すると影響が大きいということで、妥協した状態(--illegal-access=permit:Relaxedstrong encapsulation)で導入され、JDK内部APIを利用しない実装へ改修するための移行期間を設けていたしかし次のLTS(Long Term Support)候補であるJDK 17のリリース(2021年9月予定)が見えてきた今(JDK 16 リリース時)、次の段階(--illegal-access=deny:Strong encapsulation)に進むことになる8
  • 9.
  • 10.
    モジュール化従来のJARファイルmodule foo {exportsbar;opens fizz;requires buzz;}モジュール定義module-infoモジュラJARファイル10
  • 11.
    アクセス制御はモジュール定義に従うmodule-infomodule-infoDirectReflectionDeep
Reflectionmodule bar {exportsa;}module-infomodule fizz {exports c;opens c;}module foo {requires bar;requires buzz;}module-infomodule buzz {exports b;opens b;}<凡例>  :モジュール定義に従いアクセスできない(例外発生) 11foo barfizzbuzz
  • 12.
  • 13.
    モジュール対応状況と配備場所Unnamed Modules--class-path --module-path従来のJARファイル従来のJARファイルmodule-infoモジュラJARファイルmodule-infoモジュラJARファイルmodule-infoAutomatic ModulesNamed Modules無視生成13JARファイル名 モジュール名module-info生成モジュール名がない!module-info生成モジュール名がない!
  • 14.
    Unnamed / AutomaticModulesの扱いモジュール定義 Unnamed Modules Automatic Modulesname なしJarファイル名 または、JarファイルのMANIFEST属性で指定requiresALL-MODULE-PATHALL-UNNAMEDALL-SYSTEMALL-MODULE-PATHALL-UNNAMEDALL-SYSTEMexports *(全て公開) *(全て公開)opens *(全て許可) *(全て許可)14
  • 15.
    モジュールの分類System ModulesUnnamed ModulesAutomatic ModulesNamed Modulesmodule-infofizzmodule-infomodule-info15module-info⁉モジュール名がない!経過措置:将来は削除される予定だが、JDK 16 でも継続されるJARファイル名 モジュール名
  • 16.
  • 17.
    モジュールの分類System ModulesUnnamed ModulesAutomatic ModulesNamed Modulesmodule-infofizzmodule-infomodule-info17module-info⁉モジュール名がない! JARファイル名 モジュール名再掲載
  • 18.
    module-infoAutomatic ModulesUnnamed Modules→ Automatic ModulesUnnamed Modules18⁉module-infoモジュール名がない!Unnamed Modules は、Automatic Modules を含む全てのモジュールを参照(requires)と定義されているJARファイル名 モジュール名module fileA {exports *;opens *;}全てのパッケージを公開全てのパッケージへの Deep Reflection を許可<凡例>   :モジュール定義に従いアクセス制御されるDirectReflectionDeep
Reflection
  • 19.
    module-infoAutomatic ModulesAutomatic Modules→ Unnamed ModulesUnnamed Modules19DirectReflectionDeep
Reflectionmodule ⁉ {exports *;opens *;}全てのパッケージを公開全てのパッケージへの Deep Reflection を許可⁉module-infoAutomatic Modules は、Unnamed Modules を含む全てのモジュールを参照(requires)と定義されているモジュール名がない! JARファイル名 モジュール名<凡例>   :モジュール定義に従いアクセス制御される
  • 20.
    Unnamed Modules →Named Modules⁉module-infoモジュール名がない!fizzmodule-infoNamed ModulesUnnamed Modules は、Named Modules を含む全てのモジュールを参照(requires)と定義されている<凡例>   :モジュール定義に従いアクセス制御されるDirectReflectionDeep
Reflectionmodule fizz {exports D;opens D;}モジュール定義の内容は、モジュール毎に異なるUnnamed Modules20
  • 21.
    module-infoAutomatic ModulesAutomatic Modules→ Named Modules21JARファイル名 モジュール名<凡例>   :モジュール定義に従いアクセス制御されるfizzmodule-infoNamed ModulesDirectReflectionDeep
ReflectionAutomatic Modules は、Named Modules を含む全てのモジュールを参照(requires)と定義されているmodule fizz {exports D;opens D;}モジュール定義の内容は、モジュール毎に異なる
  • 22.
    Named Modules →Unnamed ModulesUnnamed Modulesfizzmodule-infoNamed Modules22DirectReflectionDeep
Reflection⁉<凡例>  :Named Modules のモジュール定義にて requires 指定できないので、アクセスできないmodule ⁉ {exports *;opens *;}Unnamed Modules は、モジュール名がないmodule-infoモジュール名がない!Named Modules は、参照したいモジュールをrequires で定義する必要がある
  • 23.
    module-infoAutomatic ModulesNamed Modules→ Automatic Modules23JARファイル名 モジュール名<凡例>   :モジュール定義に従いアクセス制御されるfizzmodule-infoNamed Modulesmodule fizz {exports D;opens D;requires fileA;}Named Modules は、参照したいモジュールをrequires で定義する必要があるmodule fileA {exports *;opens *;}全てのパッケージを公開全てのパッケージへの Deep Reflection を許可DirectReflectionDeep
Reflection
  • 24.
    module-infoAutomatic ModulesAutomatic Modules→ System Modules24DirectReflectionDeep
ReflectionAutomatic Modules は、System Modules を含む全てのモジュールを参照(requires)と定義されているJARファイル名 モジュール名System Modulesmodule-infomodule buzz {exports D;}モジュール定義の内容は、モジュール毎に異なる<凡例>   :モジュール定義に従いアクセス制御される
  • 25.
    Unnamed Modules →System Modules25System Modulesmodule-infoUnnamed Modules⁉module-infoモジュール名がない!module buzz {exports D;}Unnamed Modules は、System Modules を含む全てのモジュールを参照(requires)と定義されているDirectReflectionDeep
Reflection!--illegal-access=permitJDK 15 以前の挙動! !<凡例>   :モジュール定義に反して常にアクセス可能(警告メッセージ)!
  • 26.
    モジュール定義に反して常にアクセス可能$ java --show-versionMain2.javaopenjdk 15.0.2 2021-01-19OpenJDK Runtime Environment (build 15.0.2+7-27)OpenJDK 64-Bit Server VM (build 15.0.2+7-27, mixed mode, sharing)WARNING: An illegal reflective access operation has occurredWARNING: Illegal reflective access by Main2 (file:/2021/Main2.java) to methodjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean)WARNING: Please consider reporting this to the maintainers of Main2WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operationsWARNING: All illegal access operations will be denied in a future release26
  • 27.
    Unnamed Modules →System Modules27System Modulesmodule-infoUnnamed Modules⁉module-infoモジュール名がない!module buzz {exports D;}モジュール定義の内容は、モジュール毎に異なるUnnamed Modules は、System Modules を含む全てのモジュールを参照(requires)と定義されているDirectReflectionDeep
Reflection--illegal-access=denyJDK 16 以降の挙動<凡例>   :モジュール定義に従いアクセス制御される
  • 28.
    モジュール定義に従いアクセス制御される$ java --show-versionMain2.javaopenjdk 16 2021-03-16OpenJDK Runtime Environment (build 16+35-2229)OpenJDK 64-Bit Server VM (build 16+35-2229, mixed mode, sharing)java.lang.reflect.InaccessibleObjectException: Unable to make private booleanjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean) accessible: module java.basedoes not "opens java.util.concurrent" to unnamed module @7f416310at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:357)at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)at Main3.main(Main2.java:18)28RuntimeException
  • 29.
    JDK内部APISystem Modules の非公開なAPIのうち、--illegal-access=deny の影響を受ける箇所(分類)を知る!
  • 30.
    JDK内部API本来、アプリケーションやライブラリで利用されることを想定していない非公開な API であり、sun.*や com.sun.* または jdk.* パッケージなど…ここでは、以下の3つに分類する代替APIが存在する影響が大きいその他30System Modulesmodule-info
  • 31.
    代替APIが存在する JDK内部APIhttps://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+Tool 31JDK8の時点で既に代替APIが提供されており、現在は削除されている標準APIJDK内部API標準APIJDK内部API
  • 32.
    影響が大きい JDK内部API重要な機能を提供しているが、現時点でも代替APIが存在しない…経過措置:jdk.unsupported モジュールに格納されて提供されている将来は削除される予定だが、JDK16 でも継続されるsun.misc.Signalsun.misc.SignalHandlersun.misc.Unsafesun.reflect.Reflection::getCallerClass(int)sun.reflect.ReflectionFactorycom.sun.nio.file.ExtendedCopyOptioncom.sun.nio.file.ExtendedOpenOptioncom.sun.nio.file.ExtendedWatchEventModifiercom.sun.nio.file.SensitivityWatchEventModifier$ java --describe-module jdk.unsupportedjdk.unsupported@16exports com.sun.nio.fileexports sun.miscexports sun.reflectrequires java.base mandatedopens sun.miscopens sun.reflectJDK 9 で代替APIが提供されたのでJDK 11で削除された32
  • 33.
    その他 JDK内部API① 他の分類に該当しない、sun.*や com.sun.* パッケージなどの非公開パッケージJDK 9以降の環境では、基本的にカプセル化されている(アクセス不可)経過措置(JDK15まで):実行時に限り、Unnamed module に対して公開 (exports)② 全パッケージに含まれる private クラスやメソッド、フィールドなど…Deep Reflection によるアクセスを必須とする経過措置(JDK15まで):Unnamed module に対して deep reflection を許可 (opens)33
  • 34.
    JDK内部APIの分類とその影響JEP 396(--illegal-access のパラメータをpermit から deny に変更)の影響がJDK内部APIの分類に応じて異なるJDK内部APIの分類 --illegal-access=permit --illegal-access=deny代替APIが存在する ❌(NoClassDefFoundError などが発生)❌(NoClassDefFoundError などが発生)影響が大きい(jdk.unsupported モジュール)✔ ✔その他 ✔ ❌(InaccessibleObjectException などが発生)<凡例> ✔:問題なくアクセス可能 ❌:アクセス不可(例外が発生する)34JDK 16 のデフォルト値
  • 35.
  • 36.
    Unnamed Module による許可されていないJDK内部APIへのアクセスに対する挙動を、パラメータ値に応じて制御する--illegal-accessのパラメータと挙動パラメータ値 初回アクセス 2回目以降のアクセス 補足permit △ ✔ JDK 9 ∼15のデフォルト値warn △ △ ーdebug△(スタックトレースも出力)△(スタックトレースも出力)ーdeny ❌ ❌ JDK 16以降のデフォルト値<凡例> ✔:問題なくアクセス可能 △:アクセス可能(但し、警告メッセージを出力) ❌:アクセス不可(例外が発生する)36
  • 37.
    --illegal-access=warn の場合$ java--show-version --illegal-access=warn Main2.javaopenjdk 15.0.2 2021-01-19OpenJDK Runtime Environment (build 15.0.2+7-27)OpenJDK 64-Bit Server VM (build 15.0.2+7-27, mixed mode, sharing)WARNING: Illegal reflective access by Main2 (file:/2021/Main2.java) to methodjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean)WARNING: Illegal reflective access by Main2 (file:/2021/Main2.java) to methodjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean)WARNING: Illegal reflective access by Main2 (file:/2021/Main2.java) to fieldcom.sun.crypto.provider.BlowfishConstants.BLOWFISH_BLOCK_SIZE37警告メッセージ(許可されないアクセスの回数分)
  • 38.
    --illegal-access=debug の場合$ java--show-version --illegal-access=debug Main2.javaopenjdk 15.0.2 2021-01-19OpenJDK Runtime Environment (build 15.0.2+7-27)OpenJDK 64-Bit Server VM (build 15.0.2+7-27, mixed mode, sharing)WARNING: Illegal reflective access by Main2 (file:/2021/Main2.java) to methodjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean)at Main2.main(Main2.java:18)WARNING: Illegal reflective access by Main2 (file:/2021/Main2.java) to methodjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean)at Main2.main(Main2.java:26)WARNING: Illegal reflective access by Main2 (file:/2021/Main2.java) to fieldcom.sun.crypto.provider.BlowfishConstants.BLOWFISH_BLOCK_SIZEat Main2.main(Main2.java:35)38警告メッセージとスタックトーレス(許可されないアクセスの回数分)
  • 39.
  • 40.
    JDK内部APIの分類とその影響JEP 396(--illegal-access のパラメータをpermit から deny に変更)の影響がJDK内部APIの分類に応じて異なるJDK内部APIの分類 --illegal-access=permit --illegal-access=deny代替APIが存在する ❌(NoClassDefFoundError などが発生)❌(NoClassDefFoundError などが発生)影響が大きい(jdk.unsupported モジュール)✔ ✔その他 ✔ ❌(InaccessibleObjectException などが発生)<凡例> ✔:問題なくアクセス可能 ❌:アクセス不可(例外が発生する)40JDK 16 のデフォルト値再掲載
  • 41.
    JDK内部APIを利用するコード例try {sun.misc.BASE64Encoder b64= new sun.misc.BASE64Encoder();System.out.println(b64.encode(new byte[]{1, 2, 3}));} catch (Throwable ex) { ex.printStackTrace(); }try {Field field = sun.misc.Unsafe.class.getDeclaredField(“theUnsafe");field.setAccessible(true);sun.misc.Unsafe unsafe = (sun.misc.Unsafe) field.get(null);} catch (Exception ex) { ex.printStackTrace(); }try {java.util.conccurent.ThreadPoolExecutor executor =new ThreadPoolExecutor(5, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());Method addWorker = ThreadPoolExecutor.class.getDeclaredMethod(“addWorker", Runnable.class, Boolean.TYPE);addWorker.setAccessible(true);addWorker.invoke(executor, null, Boolean.FALSE);} catch (Exception ex) { ex.printStackTrace(); }その他41Deep Reflection代替APIが存在する影響が大きい
  • 42.
    jdeps ツールで確認⁉$ jdeps--jdk-internals --class-path test.legacy.main.jartest.legacy.main.jar -> jdk8internalstest.legacy.main.jar -> jdk.unsupportedtest.main.Main -> sun.misc.BASE64Encoder JDK internal API (jdk8internals)test.main.Main -> sun.misc.Unsafe JDK internal API (jdk.unsupported)警告: JDK内部APIはサポートされておらず、JDK実装専用ですが、互換性なしで削除または変更される場合があり、アプリケーションを中断させる可能性があります。JDK内部APIの依存性を削除するようコードを変更してください。JDK内部APIの置換に関する最新の更新については、次を確認してください:https://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+ToolJDK内部API 修正候補-------- ----sun.misc.BASE64Encoder Use java.util.Base64 @since 1.8sun.misc.Unsafe See http://openjdk.java.net/jeps/26042
  • 43.
    jdeps ツールで確認する際の注意点--jdk-internals オプションで確認できるJDK内部API の種類は限られる!JDK内部APIの分類 jdepsツールでの確認 例代替APIが存在する ✔ sun.misc.BASE64Decodersun.reflect.Reflection.getCallerClass影響が大きい(jdk.unsupported モジュール)✔ sun.misc.Unsafecom.sun.nio.file.ExtendedCopyOptionその他 ❌java.util.concurrent.ThreadPoolExecutor.addWorkerjava.security.MessageDigest.providersun.security.util.SecurityConstants<凡例> ✔:確認できる ❌:確認できない43direct アクセスの箇所のみ検出できる
  • 44.
    ⁉setAccessible(true) の箇所を特定⁉全てのソースコード(商用版を含む)を保持しているなら可能かもねぇ…OSSの場合でもマイナーバージョンまで完全把握していないとねぇ…System modules以外のモジュールに対する箇所もヒットするけどねぇ…やらないより、やる価値はあるので、自作のソースコードだけでも!44
  • 45.
    JDK 16 以降に向けた準備・確認以下のようにJEP 396 による影響を確認する1.--illegal-access=debug を明示的に指定して Java VM を起動する警告メッセージとスタックトレースを基に修正すべき箇所を確認する2.--illegal-access=deny を明示的に指定して Java VM を起動する例外が発生することなく、アプリケーションが正常動作することを確認する45
  • 46.
  • 47.
    JDK 16 では、やっぱり例外発生!$java --show-version Main3.javaopenjdk 16 2021-03-16OpenJDK Runtime Environment (build 16+35-2229)OpenJDK 64-Bit Server VM (build 16+35-2229, mixed mode, sharing)java.lang.reflect.InaccessibleObjectException: Unable to make private booleanjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean) accessible: module java.basedoes not "opens java.util.concurrent" to unnamed module @7f416310at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:357)at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)at Main3.main(Main3.java:18)47RuntimeException
  • 48.
    ソースコード修正なしに対処するには…$ java --show-version--add-opens java.base/java.util.concurrent=ALL-UNNAMED Main3.javaopenjdk 16 2021-03-16OpenJDK Runtime Environment (build 16+35-2229)OpenJDK 64-Bit Server VM (build 16+35-2229, mixed mode, sharing)48この対処は、リスクをともなうので注意が必要であるモジュール提供者の意思に反している!JDK内部APIが変更・削除された場合、失敗する!
  • 49.
    JDK 16 では--illegal-access は deprecated$ java --show-version --illegal-access=permit Main3.javaOpenJDK 64-Bit Server VM warning: Option --illegal-access is deprecated and will be removed in a future release.openjdk 16 2021-03-16OpenJDK Runtime Environment (build 16+35-2229)OpenJDK 64-Bit Server VM (build 16+35-2229, mixed mode, sharing)WARNING: An illegal reflective access operation has occurredWARNING: Illegal reflective access by Main3 (file:/2021/Main3.java) to methodjava.util.concurrent.ThreadPoolExecutor.addWorker(java.lang.Runnable,boolean)WARNING: Please consider reporting this to the maintainers of Main3WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operationsWARNING: All illegal access operations will be denied in a future release49警告メッセージ(初回アクセス分のみ)
  • 50.
  • 51.
    JEP 396での変更点従来(JDK 9∼ 15)--illegal-access=permit をデフォルト設定としてJava VMが起動する今後(JDK 16以降)--illegal-access=deny をデフォルト設定としてJava VMが起動する51再掲載
  • 52.
    Unnamed Modules →System Modules52System Modulesmodule-infoUnnamed Modules⁉module-infoモジュール名がない!module buzz {exports D;}モジュール定義の内容は、モジュール毎に異なるUnnamed Modules は、System Modules を含む全てのモジュールを参照(requires)と定義されているDirectReflectionDeep
Reflection--illegal-access=permitJDK 15 以前の挙動 再掲載! !<凡例>   :モジュール定義に反して常にアクセス可能(警告メッセージ)!!
  • 53.
    Unnamed Modules →System Modules53System Modulesmodule-infoUnnamed Modules⁉module-infoモジュール名がない!module buzz {exports D;}モジュール定義の内容は、モジュール毎に異なるUnnamed Modules は、System Modules を含む全てのモジュールを参照(requires)と定義されているDirectReflectionDeep
Reflection--illegal-access=denyJDK 16 以降の挙動<凡例>   :モジュール定義に従いアクセス制御される再掲載
  • 54.
    その他 JDK内部API① 他の分類に該当しない、sun.*や com.sun.* パッケージなどの非公開パッケージJDK 9以降の環境では、基本的にカプセル化されている(アクセス不可)経過措置(JDK15まで):実行時に限り、Unnamed module に対して公開 (exports)② 全パッケージに含まれる private クラスやメソッド、フィールドなど…Deep Reflection によるアクセスを必須とする経過措置(JDK15まで):Unnamed module に対して deep reflection を許可 (opens)54再掲載
  • 55.
    JDK 16 以降に向けた準備・確認以下のようにJEP 396 による影響を確認する1.--illegal-access=debug を明示的に指定して Java VM を起動する警告メッセージとスタックトレースを基に対処すべき箇所を確認する2.--illegal-access=deny を明示的に指定して Java VM を起動する例外が発生することなく、アプリケーションが正常動作することを確認する55再掲載
  • 56.
    --add-opens/--add-exports のリスク$ java--show-version --add-opens java.base/java.util.concurrent=ALL-UNNAMED Main2.javaopenjdk 16 2021-03-16OpenJDK Runtime Environment (build 16+35-2229)OpenJDK 64-Bit Server VM (build 16+35-2229, mixed mode, sharing)56この対処は、リスクをともなうので注意が必要であるモジュール提供者の意思に反している!JDK内部APIが変更・削除された場合、失敗する!
  • 57.
  • 58.
    参考情報JDK 16 -OpenJDK -https://openjdk.java.net/projects/jdk/16/JEP 396: Strongly Encapsulate JDK Internals by Defaulthttps://openjdk.java.net/jeps/396Relaxed Strong encapsulation - JEP 261: Module System -https://openjdk.java.net/jeps/261#Relaxed-strong-encapsulation58
  • 59.
    参考情報JEP 260: EncapsulateMost Internal APIshttps://openjdk.java.net/jeps/260Replace uses of the JDK’s internal APIs - Java Dependency Analysis Tool -https://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+ToolInternal packages that will no longer be open by default 
/ Exported packages that will no longer be open by defaulthttps://cr.openjdk.java.net/~mr/jigsaw/jdk8-packages-denied-by-default59
  • 60.
    その他使ってみよう!JDK Flight Recorderhttps://www.slideshare.net/tokumasu123/jdk-flight-recorder-126001298ログ出力を改めて考える- JDK Flight Recorder の活用 -https://www.slideshare.net/tokumasu123/jdk-flight-recorder-155345312JFR Event Streaming によるAP監視 - JDK Flight Recorder の活用 -https://www.slideshare.net/tokumasu123/jfr-event-streamingap-jdk-flight-recorder60
  • 61.
    END“JDK 16 で導入されたJEP 396 にご注意”JEP 396 : Strongly Encapsulate JDK Internals by Default

[8]ページ先頭

©2009-2025 Movatter.jp