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


91

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

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
[]

が欠落しているClassNotFoundExceptionので、それがをスローすると予想していまし@Aた。しかし、代わりに、それは静かに注釈を落とします。

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

javax.annotation.Nonnull@Retention(CLASS)とにかくそうであるはずだったように)のようなものには便利なようですが、他の多くの注釈では、実行時にさまざまな悪いことが発生する可能性があるようです。

回答:


90

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

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

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


35

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の要素がある場合、mがローカル変数宣言に注釈を付けない限り、Javaコンパイラーは、aが出現するクラスまたはインターフェースのバイナリー表現でaが表されることを確認する必要があります。 。ローカル変数宣言の注釈は、バイナリ表現では保持されません。

Tがannotation.Retentionに対応する(メタ)アノテーションmを持たない場合、JavaコンパイラーはTを、値がannotation.RetentionPolicy.CLASSである要素を持つメタアノテーションmを持っているかのように処理する必要があります。

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


9

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.