Javaで注釈を拡張できないのはなぜですか?
-
06-07-2019 - |
質問
Javaクラスのように、Javaアノテーションに継承がない理由がわかりません。とても便利だと思います。
たとえば、特定の注釈がバリデーターかどうかを知りたい。継承を使用すると、このアノテーションが ValidatorAnnotation
を拡張するかどうかを知るために、スーパークラスを再帰的にナビゲートできます。それ以外の場合、どうすればこれを達成できますか?
では、この設計上の決定の理由を教えてもらえますか?
解決
そのように設計されていない理由については、 JSR 175 設計に関するよくある質問:
なぜアノテーションサブタイピングをサポートしないのですか(あるアノテーションタイプが別のアノテーションタイプを拡張する場合)?
注釈タイプが複雑になります システム、およびそれははるかになります 書くのが難しい“特定のツール”。
…
“特定のツール” —クエリするプログラム 任意の既知の注釈タイプ 外部プログラム。スタブジェネレーター、 たとえば、このカテゴリに分類されます。 これらのプログラムは注釈付きで読みます にロードせずにクラス 仮想マシン、ただしロードする 注釈インターフェース。
それで、はい、私は推測します、その理由はただのKISSです。とにかく、この問題は(他の多くと一緒に) JSR 308の一部として検討されているようです。 、およびによって既に開発されているこの機能を備えた代替コンパイラも見つけることができます。マティアス・リッケン。
他のヒント
拡張可能な注釈は、別の型システムを指定および維持する負担を効果的に追加します。そして、これはかなりユニークな型システムになるので、オブジェクト指向型パラダイムを単純に適用することはできません。
アノテーションにポリモーフィズムと継承を導入する際にすべての問題を考えてください(たとえば、サブアノテーションが保持などのメタアノテーション仕様を変更するとどうなりますか?)
そして、これらすべてが、どのようなユースケースに複雑さを追加しましたか?
特定の注釈がカテゴリに属しているかどうかを知りたいですか?
これを試してください:
@Target(ElementType.ANNOTATION_TYPE)
public @interface Category {
String category();
}
@Category(category="validator")
public @interface MyFooBarValidator {
}
ご覧のとおり、提供されている機能を使用すると、苦痛を伴うことなく、注釈を簡単にグループ化および分類できます。
そのため、 KISS は、Javaにメタタイプタイプシステムを導入しない理由です。言語。
[p.s。編集]
文字列は、単にデモンストレーションのために、またオープンエンドのメタアノテーションを考慮して使用しました。独自のプロジェクトでは、カテゴリタイプの列挙を使用して、特定のアノテーションに複数のカテゴリ(「多重継承」)を指定できます。値は完全に偽であり、デモンストレーションのみを目的としています。
@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 {
}
ある意味で、あなたはすでに注釈を付けています-メタ注釈。メタ情報で注釈に注釈を付けると、多くの点で追加のインターフェースを拡張することに相当します。注釈はインターフェースであるため、ポリモーフィズムは実際には作用しません。また、それらは本質的に静的であるため、実行時の動的ディスパッチはありません。
バリデータの例では、注釈で注釈付きの型を取得し、バリデータのメタ注釈があるかどうかを確認できます。
継承が役立つことがわかる唯一のユースケースは、スーパータイプで注釈を取得できるようにする場合ですが、特定のメソッドまたはタイプにはそのような注釈が2つあるため、かなり複雑になりますつまり、単一のオブジェクトの代わりに配列を返す必要があることを意味します。
したがって、究極の答えは、ユースケースが難解であり、より標準的なユースケースを複雑にして価値がないと考えることです。
Javaアノテーションサポートの設計者は、多くの「簡素化」を行いました。 Javaコミュニティに不利益をもたらします。
-
アノテーションサブタイプがないため、多くの複雑なアノテーションが不必要に見苦しくなります。次の3つのいずれかを保持できるアノテーション内の属性を単純に持つことはできません。 3つの別個の属性が必要です。これにより、開発者は混乱し、3つのうち1つだけが使用されることを確認するためにランタイム検証が必要になります。
-
サイトごとに特定のタイプの注釈が1つだけ。これは、完全に不要なコレクション注釈パターンにつながりました。 @Validationおよび@ Validations、@ Imageおよび@Imagesなど。
2つ目はJava 8で修正されていますが、手遅れです。多くのフレームワークはJava 5で可能だったものに基づいて記述されており、これらのAPIイボは長い間存在するためにここにあります。
考えられることの1つは、複数の注釈を持つ可能性です。そのため、同じ場所にバリデータとより具体的な注釈を追加できます。しかし、私は間違っている可能性があります:)
それについて考えたことはありませんが、...あなたは正しいようです、アノテーション継承機能に問題はありません(少なくとも私はそれに関する問題を見ません)。
'validator' アノテーションを使用したサンプルについて- 'meta-annotation' アプローチを活用できます。つまり特定のメタ注釈を注釈インターフェース全体に適用します。
この質問に答えるのに3年遅れるかもしれませんが、同じ場所にいるので面白かったです。これが私の見解です。注釈を列挙として表示できます。それらは一方向の情報を提供します-それを使用するか、それを失います。
WebアプリでGET、POST、PUT、DELETEをシミュレートしたい状況がありました。私はひどく「スーパー」を持ちたかった「HTTP_METHOD」と呼ばれる注釈。後でそれが重要ではないことがわかりました。さて、HTMLフォームの非表示フィールドを使用してDELETEとPUTを特定する必要がありました(とにかくPOSTとGETを使用できたため)。
サーバー側で、" _method"という名前の非表示の要求パラメーターを探しました。値がPUTまたはDELETEの場合、関連するHTTP要求メソッドを無効にしました。そうは言っても、作業を完了するために注釈を拡張する必要があるかどうかは関係ありません。すべての注釈は同じように見えましたが、サーバー側では異なる方法で処理されました。
したがって、あなたの場合は、かゆみを落として注釈を拡張します。それらを「マーカー」として扱います。それらは「代表する」一部の情報であり、必ずしも「操作」する必要はありません。いくつかの情報。
私と同じ問題。いいえ、できません。私はいくつかの標準を尊重するために注釈でプロパティを記述するように「規律」しました。そのため、注釈を取得するときは、それがどのような注釈であるかを特性によって「盗聴」できます。