web-dev-qa-db-ja.com

欠落したアノテーションが実行時にClassNotFoundExceptionを引き起こさないのはなぜですか?

次のコードを検討してください。

A.Java:

_import Java.lang.annotation.Retention;
import Java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@interface A{}
_

C.Java:

_import Java.util.*;

@A public class C {
        public static void main(String[] args){
                System.out.println(Arrays.toString(C.class.getAnnotations()));
        }
}
_

コンパイルと実行は期待どおりに機能します。

_$ javac *.Java
$ Java -cp . C
[@A()]
_

しかし、これを考慮してください:

_$ rm A.class
$ Java -cp . C
[]
_

_@A_がないため、ClassNotFoundExceptionがスローされると思っていました。しかし、代わりに、それは静かに注釈を落とします。

この動作はどこかでJLSに文書化されていますか、それともSunのJVMの癖ですか?その理由は何ですか?

_javax.annotation.Nonnull_(とにかく@Retention(CLASS)である必要があるようです)のようなものには便利なようですが、他の多くの注釈では、実行時にさまざまな問題が発生する可能性があるようです。

86
Matt McHenry

JSR-175(注釈)の以前の公開草案では、注釈の使用法と宣言の間の疎結合を提供するために、コンパイラとランタイムが不明な注釈を無視すべきかどうかが議論されました。具体的な例としては、EJBでアプリケーションサーバー固有のアノテーションを使用してデプロイメント構成を制御する場合が挙げられます。同じBeanを別のアプリケーションサーバーにデプロイする必要がある場合、ランタイムがNoClassDefFoundErrorを発生させるのではなく、不明な注釈を単に無視すれば便利でした。

表現が少しあいまいでも、JLS 13.5.7で表示されている動作が指定されていると思います:「...アノテーションを削除しても、Javaプログラミング言語。」私はこれを注釈が削除された(実行時には使用できない)場合と解釈します。プログラムは引き続きリンクして実行する必要があります。これは、リフレクションを通じてアクセスしたときに不明な注釈が単に無視されることを意味します。

SunのJDK 5の最初のリリースはこれを正しく実装していませんでしたが、1.5.0_06で修正されました。関連するバグ 6322301 はバグデータベースで見つけることができますが、「JSR-175スペックリードによれば、不明なアノテーションはgetAnnotationsによって無視する必要がある」と主張する以外は仕様を指していません。

86
jarnbjo

JLSの引用:

9.6.1.2保持注釈は、ソースコードにのみ存在するか、クラスまたはインターフェイスのバイナリ形式で存在する可能性があります。 バイナリに存在する注釈は、Javaプラットフォーム。のリフレクトライブラリを介して実行時に利用できる場合と利用できない場合があります。

注釈タイプannotation.Retentionは、上記の可能性の中から選択するために使用されます。注釈aがタイプTに対応し、Tがannotation.Retentionに対応する(メタ)注釈mを持っている場合:

  • Mに値がannotation.RetentionPolicy.SOURCEである要素がある場合、Javaコンパイラは、aが出現するクラスまたはインターフェイスのバイナリ表現にaが存在しないことを確認する必要があります。
  • Mに値がannotation.RetentionPolicy.CLASS、またはannotation.RetentionPolicy.RUNTIMEである要素がある場合、a Javaコンパイラは、aがクラスまたはクラスのバイナリ表現で表されることを確認する必要があります。 mがローカル変数宣言に注釈を付けない限り、ローカル変数宣言の注釈がバイナリ表現に保持されることはありません。

Tが注釈に対応する(メタ)注釈mを持たない場合、a JavaコンパイラはTをそのような要素を持つメタ注釈mを持っているかのように扱う必要があります。値はannotation.RetentionPolicy.CLASSです。

したがって、RetentionPolicy.RUNTIMEは、注釈がバイナリにコンパイルされることを保証しますが、バイナリに存在する注釈は実行時に利用可能である必要はありません

32
Guillaume

実際に@Aを読み取って何かを行うコードがある場合、そのコードはクラスAに依存しており、ClassNotFoundExceptionをスローします。

そうでない場合、つまり、@ Aを特に気にするコードがない場合、@ Aが実際には問題にならないことは間違いありません。

7
irreputable