Javaでアノテーションを拡張できないのはなぜですか?


227

Javaクラスのように、Javaアノテーションに継承がない理由がわかりません。とても重宝すると思います。

例:特定の注釈がバリデーターかどうかを知りたい。継承により、スーパークラスを反射的にナビゲートして、このアノテーションがを拡張するかどうかを知ることができValidatorAnnotationます。そうでなければ、どうすればこれを達成できますか?

それで、誰かが私にこの設計決定の理由を教えてもらえますか?


2
ところで、この事実は明示的に宣言されていませんjava.lang.annotation.Annotationが、すべての注釈が拡張されることに注意してくださいinstanceof
トマーシュZáluský

回答:


166

このように設計されていない理由については、JSR 175設計FAQで答えを見つけることができます。

アノテーションのサブタイピング(あるアノテーションタイプが別のアノテーションタイプを拡張する)をサポートしないのはなぜですか?

これは注釈型システムを複雑にし、「特定のツール」を書くことをはるかに困難にします。

「特定のツール」—任意の外部プログラムの既知の注釈タイプを照会するプログラム。たとえば、スタブジェネレータはこのカテゴリに分類されます。これらのプログラムは、注釈付きクラスを仮想マシンに読み込まずに読み取りますが、注釈インターフェイスを読み込みます。

だから、はい、私は推測します、理由はそれがただのキスであることです。とにかく、この問題は(他の多くの問題とともに)JSR 308の一部として調査されているようです。また、Mathias Rickenによってすでに開発されているこの機能を備えた代替コンパイラを見つけることもできます。


67
まあ、私は愚かかもしれませんが、「シンプルに保つ」ためだけにアノテーションを拡張することはできません。少なくとも、Javaデザイナーはクラス継承について同じことを考えていませんでした:P
sinuhepop 2009年

2
Java 8 M7は、サブクラス化アノテーションをサポートしていないようです。お気の毒に。
Ceki 2013

2
@assylias JEP 104は、アノテーションをサブクラス化することを可能にするものではありません。JEP 104はJava 8で実装されましたが、アノテーションをサブクラス化することはまだできません(あるアノテーションを別のアノテーションに拡張する)。
Jesper、

71

拡張可能な注釈は、別の型システムを指定および維持する負担を効果的に追加します。そして、これはかなりユニークな型システムになるので、単にOO型のパラダイムを適用することはできません。

アノテーションにポリモーフィズムと継承を導入するときは、すべての問題を検討してください(たとえば、サブアノテーションが保持などのメタアノテーション仕様を変更するとどうなりますか?)

そして、これらすべてがどのようなユースケースに複雑さを追加しましたか?

特定の注釈がカテゴリに属しているかどうかを知りたいですか?

これを試して:

@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
    String category();
}

@Category(category="validator")
public @interface MyFooBarValidator {

}

ご覧のとおり、提供されている機能を使用して、過度の苦痛なしに注釈を簡単にグループ化および分類できます。

したがって、KISSはメタ型の型システムをJava言語に導入しない理由です。

[ps編集]

私はStringを単にデモンストレーションのために、そしてオープンエンドのメタ注釈を考慮して使用しました。独自の特定のプロジェクトでは、カテゴリタイプの列挙を使用して、特定の注釈に複数のカテゴリ(「多重継承」)を指定できます。値は完全に偽であり、デモンストレーションのみを目的としていることに注意してください。

@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
    AnnotationCategory[] category();
}
public enum AnnotationCategory {
    GENERAL,
    SEMANTICS,
    VALIDATION,
    ETC
}

@Category(category={AnnotationCategory.GENERAL, AnnotationCategory.SEMANTICS})
public @interface FooBarAnnotation {

}


しないの仕事はfalseを出力します:@Target(ElementType.ANNOTATION_TYPE) @Retention(RetentionPolicy.RUNTIME) @interface C {}; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @C public @interface F {} class a{ @F public void S() {} } @Test public void blahTest() throws NoSuchMethodException { Method m = a.class.getMethod("S"); System.out.println(m.isAnnotationPresent(C.class)); }
user1615664

注釈を付けています。a#Sには注釈Fがあります。F自体にはCによって注釈が付けられています。それを試してください。
alphazero

はい、そうです。しかし、Annotationプロキシを介して読み取るよりも、よりクリーンにそれを行う方法はありますか?
user1615664

12

ある意味では、すでにAnnotations-meta Annotationsを使用しています。メタ情報で注釈を付ける場合、それは多くの点で追加のインターフェースを拡張することと同等です。アノテーションはインターフェースであるため、ポリモーフィズムは実際には機能しません。また、アノテーションは本質的に静的であるため、実行時の動的ディスパッチはありません。

バリデーターの例では、アノテーション上でアノテーション付きタイプを取得し、バリデータメタアノテーションがあるかどうかを確認できます。

継承が役立つことがわかる唯一のユースケースは、スーパータイプでアノテーションを取得できるようにする場合ですが、特定のメソッドまたはタイプにそのようなアノテーションが2つあるため、全体の複雑さが増します。つまり、単一のオブジェクトではなく配列を返す必要があります。

したがって、最終的な答えは、ユースケースは難解であり、より標準的なユースケースが複雑になるため、価値がないということです。


5

Javaアノテーションサポートの設計者は、Javaコミュニティに不利益をもたらすいくつかの「単純化」を行いました。

  1. 注釈サブタイプがないと、多くの複雑な注釈が不必要に醜くなります。3つのうちの1つを保持できるアノテーション内に属性を単純に持つことはできません。1つは3つの個別の属性を持つ必要があり、開発者を混乱させ、3つのうちの1つだけが使用されることを確認するためにランタイム検証が必要です。

  2. サイトごとに指定されたタイプの注釈は1つだけです。これにより、完全に不要なコレクションアノテーションパターンが発生します。@Validationと@ Validations、@ Imageと@Imagesなど

2つ目はJava 8で修正中ですが、手遅れです。多くのフレームワークは、Java 5で可能なことを基に作成されており、これらのAPIのいぼは、長い間ここにとどまっています。


1
それだけでなく、属性が再帰的にネストされているプロパティを定義することもできなくなります。これはXMLスキーマでサポートされています。これにより、注釈はXMLよりも厳密に弱くなります
user2833557

3

この質問への回答は3年遅れるかもしれませんが、同じ場所にいるので興味深いと思いました。これが私の見解です。注釈を列挙として表示できます。それらは一方向の種類の情報を提供します-それを使用するか、それを失います。

WebアプリでGET、POST、PUT、DELETEをシミュレートしたい状況がありました。「HTTP_METHOD」と呼ばれる「スーパー」アノテーションが欲しいのですが。それは問題ではないことが後で私に夜明けしました。ええと、HTMLフォームの非表示フィールドを使用して、DELETEとPUTを特定する必要がありました(とにかくPOSTとGETが利用可能だったためです)。

サーバー側で、「_ method」という名前の非表示のリクエストパラメータを探しました。値がPUTまたはDELETEの場合、関連するHTTPリクエストメソッドをオーバーライドします。そうは言っても、作業を完了するためにアノテーションを拡張する必要があるかどうかは問題ではありませんでした。すべての注釈は同じように見えましたが、サーバー側では扱いが異なりました。

したがって、あなたのケースでは、注釈を拡張するためにかゆみをドロップします。それらを「マーカー」として扱います。それらは一部の情報を「表現」し、必ずしも一部の情報を「操作」するわけではありません。


2

私が考えることができる1つのことは、複数の注釈を持つ可能性です。そのため、同じ場所にバリデータとより具体的なアノテーションを追加できます。しかし、私は間違っている可能性があります:)


2

それについて考えたことはありませんが...あなたの言う通りだと思いますが、アノテーションの継承機能には問題はありません(少なくとも、問題は発生しません)。

「バリデーター」アノテーションを使用した例について-悪用することができます次に「メタアノテーション」アプローチを。つまり、特定のメタ注釈を注釈インターフェイス全体に適用します。


この質問への回答は3年遅れるかもしれませんが、同じ場所にいるので興味深いと思いました。
mainas 2013年

1

私と同じ問題。いいえ、できません。私はいくつかの標準を尊重するためにアノテーションにプロパティを書き込むように自分自身を「規律」づけたので、アノテーションを取得したときに、それが持つプロパティによってアノテーションがどのような種類のアノテーションであるかを「嗅ぐ」ことができます。

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