web-dev-qa-db-ja.com

Javaで注釈を拡張できないのはなぜですか?

Javaクラスと同様に、Javaアノテーションに継承がない理由がわかりません。とても便利だと思います。

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

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

219
sinuhepop

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

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

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

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

だから、そうだと思う、理由はただのKISSだからだ。とにかく、この問題は(他の多くの問題とともに) JSR 308 の一部として検討されているようです。 Mathias Ricken によって既に開発された機能。

159
pedromarce

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

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

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

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

これを試して:

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

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

}

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

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

[追伸編集]

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

@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 {

}

66
alphazero

ある意味で、あなたはすでにアノテーションを持っています-メタアノテーション。メタ情報で注釈に注釈を付けると、多くの点で追加のインターフェースを拡張することに相当します。アノテーションはインターフェースであるため、ポリモーフィズムは実際には作用しません。また、本質的に静的であるため、ランタイムの動的ディスパッチはありません。

バリデータの例では、注釈で注釈付きの型を取得し、バリデータのメタ注釈があるかどうかを確認できます。

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

究極の答えは、ユースケースが難解であり、より標準的なユースケースを複雑にして価値がないと考えることです。

11
Yishai

Java注釈サポートの設計者は、Javaコミュニティを損なうために、いくつかの「単純化」を行いました。

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

  2. サイトごとに特定のタイプの注釈が1つだけ。これは、完全に不必要なコレクション注釈パターンにつながりました。 @Validationおよび@ Validations、@ Imageおよび@Imagesなど。

2番目はJava 8で修正されていますが、手遅れです。多くのフレームワークはJava 5で可能だったものに基づいて記述されており、これらのAPIのいぼは長い間ここにあります。

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

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

サーバー側では、「_ method」という名前の隠された要求パラメーターを探しました。値がPUTまたはDELETEの場合、関連するHTTP要求メソッドを無効にしました。そうは言っても、作業を完了するために注釈を拡張する必要があるかどうかは関係ありません。すべての注釈は同じように見えましたが、サーバー側では異なる方法で処理されました。

したがって、あなたの場合、かゆみを落として注釈を拡張してください。それらを「マーカー」として扱います。それらはいくつかの情報を「表現」し、必ずしもいくつかの情報を「操作」するわけではありません。

2
mainas

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

2
Janusz

それについて考えたことはありませんが、...あなたは正しいようです、アノテーション継承機能に問題はありません(少なくとも私はそれに関する問題を見ません)。

'validator'注釈を使用した例については、'meta-annotation'アプローチを活用できます。つまり特定のメタ注釈を注釈インターフェース全体に適用します。

2
denis.zhdanov

私が持っている同じ問題。いいえ、できません。私はいくつかの標準を尊重するためにアノテーションでプロパティを記述するように「規律」しました。そのため、アノテーションを取得するときは、プロパティによってどのようなodアノテーションであるかを「盗聴」できます。

1
ante.sabo