読者です 読者をやめる 読者になる 読者になる

kagamihogeの日記

kagamihogeの日記です。

JEP 260: Encapsulate Most Internal APIsをテキトーに訳した

http://openjdk.java.net/jeps/260 をテキトーに訳した。

JEP 260: Encapsulate Most Internal APIs

Owner   Mark Reinhold
Created 2015/08/03 18:29
Updated 2015/08/04 21:27
Type    Feature
Status  Candidate
Scope   JDK
Discussion  jigsaw dash dev at openjdk dot java dot net
Effort  M
Duration    L
Priority    1
Reviewed by Alan Bateman, Alex Buckley, Brian Goetz, John Rose, Paul Sandoz
Release 9
Issue   8132928

Summary

JDKの内部APIの大部分をデフォルトではアクセス不能にします。ただし、少数の重要な(critical)*1ものや、広く使われているAPIは、代替実装が対象機能のすべてもしくは大部分をカバーするまで*2、アクセス可能なままにします。

Non-Goals

このJEP自体は内部APIの置換を目的とはしません。それらの置換作業は、別のJEPと、適切なJSRによって行われると思われます。

このJEPは複数リリースを越えて内部APIの互換性を維持することは約束しません。それらの内部APIはunstableのまま残り続け、予告なしの変更がありえます。

Motivation

広く使われているライブラリのいくつかはJDKの内部実装詳細を使用しており、これらの内部実装は未サポート・unstable・非標準APIで、APIは外部で使われることは想定していません。導入予定のモジュールシステム(JEP 200)を活用してこれらの内部APIへのアクセスを制限することでプラットフォームのセキュリティと整合性が改善します。その理由は、多数の内部APIが特権でセキュリティにセンシティブな操作を定義しているためです。長期的にはこの変更により、意図的かそうでないかに関わらず内部APIを使用しているライブラリおよびアプリケーションと、JDKのメンテナンスにかかるコストが減少すると考えられます。

Description

Maven Centralを含む非常に多くのコード分析と、JDK 8リリース以降のフィードバックと依存性分析ツール(jdeps)の結果に基づき、JDKの内部APIを二つの大きなカテゴリに分割しました。

  • JDK外でコードが使われていないか、ただ単に便宜上使われている内部API。つまり、サポートAPIで利用可能な機能であるか*3、ライブラリで提供することが容易です。(例:sun.misc.BASE64Decoder
  • JDK外での実装が困難か不可能な、重要な機能を提供する内部API。(例:sun.misc.Unsafe

JDK 9に向けて我々は以下の提案を行います。

  • 重要でない(non-critical)すべての内部APIをデフォルトでカプセル化します。対象モジュールが定義するAPIは外部で使えるようにはパッケージをエクスポートしません。(最後の手段として、コンパイル時および実行時の両方にコマンドラインフラグを付与することで、これらのAPIが利用可能になります。ただし、それらのAPIが何らかの理由で削除や修正がされていない場合に限ります。)
  • JDK 8で代替実装が存在する重要な内部APIカプセル化します。同様に最後の手段を設けます。(代替実装はJava SE 8標準の一部(java.もしくはjavax.パッケージ)か、JDK固有で@jdk.Exportedアノテーションが付与されているもの(通常はcom.sun.もしくはjdk.)、のどちらかになります。)
  • 重要な内部APIカプセル化しないものとしては、代替実装がJDK 8に存在しない、JDK 9でカプセル化目的の代替実装が非推奨、JDK 10で削除される可能性がある、です。

JDK 9でアクセス可能なままで残そうと考えている重要な内部APIは以下の通りです。

  • sun.misc.Cleaner
  • sun.misc.{Signal,SignalHandler}
  • sun.misc.Unsafe(このクラスのメソッドが持つ機能の多くは各種のハンドラ(JEP 193)経由で利用可能です。)
  • sun.reflect.Reflection::getCallerClass(このメソッドの機能はJEP 259経由の標準形式で提供可能です。)
  • sun.reflect.ReflectionFactory

実世界のユースケース・開発者の推測・エンドユーザへのインパクトによって正当化される、このリストへの追加提案は歓迎します。

上記の重要な内部APIと、エクスポートされたパッケージは、jdk.internalというJDK固有のモジュールに配置される予定です。このモジュールは全JREおよびJDKのイメージになります。それゆえに、クラスパス上のコードにはデフォルトでは内部APIはアクセス可能で、もしモジュールがjdk.internalモジュールに依存する宣言をする場合、内部APIモジュール内のコードにアクセス可能です*4

上述したように、内部APIの置換実装はJDK 9で全体もしくは一部が既に存在しています。開発者にはJDK 9 early-access buildsの置換実装のテストを行い、もし置換実装が不十分ないし改善が見られない場合はフィードバックを送ることを推奨します。

JDK 9で導入された置換用の重要な内部APIJDK 9で非推奨化され、JDK 10ではカプセル化もしくは削除されます。

JDK 9で置換用の重要な内部APIを使用しているライブラリの開発者は、JDK 9以前のリリースの古いAPIとそれ以降のリリースの置換APIを使用するシングルアーティファクトを構築するために、Multi-Release JAR Files (JEP 238)の使用が推奨されます*5

Risks and Assumptions

もしJDK 9がリリースされるまで広範に使われている重要な内部APIの識別が出来なかった場合、内部APIに依存するアプリケーションは動かなくなります。そのようなケースでの短期的な回避策は、上述したように、コマンドラインフラグでAPIをエンドユーザに公開することです。長期的には、JDK 9 updateリリース時にjdk.internalモジュールと外部からのアクセス用にエクスポートされたモジュールに内部APIを移動していきます。

*1:このJEPには critical internal APIsという表現が頻出する。com.sun.とかjdk.みたいな非常に根幹を成すモジュールのことをcriticalと言っている。訳は『クリティカル』にしてもよかったが『重要な』と訳すことにした

*2:until supported replacements exist for all or most of their functionality.が原文。supported replacementsだけど、このJEP読む限り『内部APIを直接触らなくて済むような置換実装』ぐらいの意味っぽいので、この抄訳では『代替実装』と訳すことにした

*3:for functionality that is available in supported APIsが原文。ありふれた機能なので置き換えるのが簡単、くらいの意味とは思う

*4: These APIs will therefore be accessible by default to code on the class path, and accessible to code in modules if those modules declare dependences upon the jdk.internal module.が原文。訳に自信が無い

*5:Maintainers of libraries that use critical internal APIs for which replacements exist in JDK 9 may wish to use Multi-Release JAR Files (JEP 238) in order to ship single artifacts that use the old APIs on releases prior to JDK 9 and the replacement APIs on later releases.が原文。ここも自信が無い…