Javaクラスが実装されたインターフェースから注釈を継承しないのはなぜですか?


108

私はGuiceのAOPを使用していくつかのメソッド呼び出しをインターセプトしています。私のクラスはインターフェースを実装しています。Guiceが適切なメソッドを選択できるように、インターフェースメソッドに注釈を付けたいと思います。Inheritedのjavaドキュメントに記載されているように、アノテーションタイプにInheritedアノテーション実装クラスでアノテーションが付けられていても、アノテーションは継承されません。

また、このメタ注釈は注釈がスーパークラスから継承されるだけであることにも注意してください。実装されたインターフェースの注釈は効果がありません。

これの理由は何でしょうか?オブジェクトのクラスが実行時に実装するすべてのインターフェースを知ることはそれほど難しいことではないので、この決定の背後には十分な理由があるはずです。

回答:


130

そうでなければ、多重継承の問題が発生するからだと思います。

例:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Inherited
public @interface Baz { String value(); }

public interface Foo{
    @Baz("baz") void doStuff();
}

public interface Bar{
    @Baz("phleem") void doStuff();
}

public class Flipp{
    @Baz("flopp") public void doStuff(){}
}

public class MyClass extends Flipp implements Foo, Bar{}

私がこれをすると:

MyClass.class.getMethod("doStuff").getAnnotation(Baz.class).value()

結果はどうなるのでしょうか?「baz」、「phleem」、または「flopp」?


このため、インターフェースの注釈が役立つことはほとんどありません。


9
インターフェースの注釈は、それらをサポートするフレームワークがある場合にのみ役立ちます。この例のBTWは、getAnnotation()がnullを返します;)
Peter Lawrey

6
わかりません、人々。この場合(タイプミスがなかった場合)、The field value is ambiguous.同じ定数を異なる値で宣言している2つのインターフェースと同様に、-のようなコンパイラエラーが発生します。これはフィールドではないことを知っていますが、注釈値はすべてコンパイル時に解決されますね。ここで欠けている機能は、多くの場合非常に役立ちます。ところで、古い投稿を復活させてすみません。
PetrJaneček2012

7
@Slanecは、Springがこれらの問題にどのように対処したかを確認するために、Springがソースを提供する方法を調べています。AnnotationUtils.findAnnotation(method、annotationType)を
Sean Patrick Floyd

1
これに似たものを書くことを考えていました。ある種の単純なキャッシングを使用すると、これは私にとって行く方法のように思えます。ありがとう!上記の例では、Fooの注釈が見つかり(注釈MyClassがない場合は、インターフェイスが検索され、その後にある順に取得されimplementsます)、したがって「baz」が出力されます。涼しい。
PetrJaneček2012

2
@WChargin true、誰かがそのタイプミスを見つけるのに2年かかった:-)
Sean Patrick Floyd

35

@Inherited のJavadocから:

注釈型が自動的に継承されることを示します。Inheritedメタアノテーションがアノテーション型宣言に存在し、ユーザーがクラス宣言でアノテーション型をクエリし、クラス宣言にこの型のアノテーションがない場合、クラスのスーパークラスは自動的にアノテーション型を照会されます。このプロセスは、このタイプの注釈が見つかるか、クラス階層(オブジェクト)の最上位に到達するまで繰り返されます。スーパークラスにこのタイプの注釈がない場合、クエリは、問題のクラスにそのような注釈がないことを示します。このメタ注釈型は、クラス以外の注釈に注釈型が使用されている場合には効果がないことに注意してください。このメタ注釈は注釈がスーパークラスから継承されるだけであることにも注意してください。

一方、JSR 305バリデーターは、ある種の継承ルックアップを行います。クラスの階層がある場合:

//Person.java
@Nonnull
 public Integer getAge() {...}

//Student.java (inherits from Person)
@Min(5)
public Integer getAge() {...}

次に、有効な検証Student.getAge()@Nonnull @Min(5)です。メタ注釈@Nonnullはありません@Inherited


4
これが選択された答えになるはずです
Andrzej Purtak

3
あなたの例はあなたの答えと矛盾します、それは@Inheritedクラス以外には何の影響も及ぼさないと言います
Oleg Mikheev

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