Javaの注釈継承のようなものはありますか?


119

私は注釈を調査していて、いくつかの注釈がそれらの間に階層を持っているように見えるようになりました。

カードのバックグラウンドでコードを生成するために注釈を使用しています。カードの種類はさまざまです(そのため、コードと注釈も異なります)が、名前のようにそれらの間で共通する特定の要素があります。

@Target(value = {ElementType.TYPE})
public @interface Move extends Page{
 String method1();
 String method2();
}

そして、これは一般的な注釈になります:

@Target(value = {ElementType.TYPE})
public @interface Page{
 String method3();
}

上記の例では、Moveがmethod3を継承することを期待していますが、extensionsはアノテーションでは無効であるという警告が表示されます。Annotationで共通の基本アノテーションを拡張しようとしたのですが、うまくいきません。それは可能ですか、それとも単なる設計上の問題ですか?


3
アノテーションの継承は、アノテーションに基づいてDSLを作成するための必須アイテムのようです。注釈の継承がサポートされていないのは残念です。
Ceki

2
同意するのは当然のことのようです。特にJavaの継承を理解した後は、それがすべてに適用されることを期待します。
javydreamercsw 2013

回答:


76

残念だけど違う。どうやら、クラスの注釈を完全に読み込まずに読み取るプログラムと関係があるようです。参照してくださいなぜJavaで注釈を拡張することが可能ではないでしょうか?

ただし、それらの注釈がである場合、型はスーパークラスの注釈を継承します@Inherited

また、これらのメソッドを操作する必要がない限り、クラスに注釈をスタックするだけです。

@Move
@Page
public class myAwesomeClass {}

うまくいかない理由はありますか?


1
それは私が思っていたものですが、私は物事を単純化しようと努めていました。多分抽象クラスに共通のものを適用するとうまくいくでしょう...
javydreamercsw

1
ええ、それもかなり賢く見えました。幸運を!
andronikus '14 / 10/14

67

継承の代わりにベースアノテーションでアノテーションを付けることができます。これはSpringフレームワークで使用されます。

例を挙げれば

@Target(value = {ElementType.ANNOTATION_TYPE})
public @interface Vehicle {
}

@Target(value = {ElementType.TYPE})
@Vehicle
public @interface Car {
}

@Car
class Foo {
}

次に、SpringのAnnotationUtilsVehicle使用してクラスに注釈が付けられているかどうかを確認できます。

Vehicle vehicleAnnotation = AnnotationUtils.findAnnotation (Foo.class, Vehicle.class);
boolean isAnnotated = vehicleAnnotation != null;

このメソッドは次のように実装されます。

public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) {
    return findAnnotation(clazz, annotationType, new HashSet<Annotation>());
}

@SuppressWarnings("unchecked")
private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, Set<Annotation> visited) {
    try {
        Annotation[] anns = clazz.getDeclaredAnnotations();
        for (Annotation ann : anns) {
            if (ann.annotationType() == annotationType) {
                return (A) ann;
            }
        }
        for (Annotation ann : anns) {
            if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
                A annotation = findAnnotation(ann.annotationType(), annotationType, visited);
                if (annotation != null) {
                    return annotation;
                }
            }
        }
    }
    catch (Exception ex) {
        handleIntrospectionFailure(clazz, ex);
        return null;
    }

    for (Class<?> ifc : clazz.getInterfaces()) {
        A annotation = findAnnotation(ifc, annotationType, visited);
        if (annotation != null) {
            return annotation;
        }
    }

    Class<?> superclass = clazz.getSuperclass();
    if (superclass == null || Object.class == superclass) {
        return null;
    }
    return findAnnotation(superclass, annotationType, visited);
}

AnnotationUtilsまた、メソッドおよびその他の注釈付き要素の注釈を検索するための追加のメソッドも含まれています。また、Springクラスは、ブリッジされたメソッド、プロキシ、およびその他の重要なケース、特にSpringで遭遇するケースを検索するのに十分強力です。


13
そのような注釈の処理方法の説明を含めてください。
Aleksandr Dubinsky

1
あなたが春のAnnotationUtils.findAnnotation(..)を使用することができ、次を参照してください。docs.spring.io/spring/docs/current/javadoc-api/org/...
rgrebski

2
注釈Aに別の注釈Bで注釈を付け、クラスCにAで注釈を付けると、クラスCはAとBの両方で注釈が付けられているかのように扱われます。これは、Springフレームワークの特定の動作です-AnnotationUtils.findAnnotationが魔法をかけますここで、アノテーションのアノテーションを見つけるために上に移動するために使用されます。したがって、これが注釈処理に関するJavaのデフォルトの動作であることを誤解しないでください。
qartal

これは、作成するアノテーションにTYPEまたはのターゲットがある場合にのみ可能ですANNOTATION_TYPE
OrangeDog

7

Grygoriysに加えて、注釈に注釈を付けます。

たとえば、このループによって、@Qualifierアノテーション(またはでアノテーションされたアノテーション@Qualifier)を含むメソッドを確認できます。

for (Annotation a : method.getAnnotations()) {
    if (a.annotationType().isAnnotationPresent(Qualifier.class)) {
        System.out.println("found @Qualifier annotation");//found annotation having Qualifier annotation itself
    }
}

基本的には、メソッドに存在するすべての注釈を取得し、それらの注釈の型を取得し、@ Qualifierで注釈が付けられている場合はそれらの型を確認します。これを機能させるには、アノテーションもTarget.Annotation_typeを有効にする必要があります。


これはグリゴリーの答えとどう違うのですか?
Aleksandr Dubinsky

@AleksandrDubinsky:これは、Springを使用しない、はるかに単純な実装です。アノテーション付きのアノテーション付きアノテーションを再帰的に検索することはありませんが、これは通常は必要ないと思います。このソリューションのシンプルさが気に入っています。
Stefan Steinegger

1

同じ質問があったときに開発したライブラリであるhttps://github.com/blindpirate/annotation-magicをチェックしてください

@interface Animal {
    boolean fluffy() default false;

    String name() default "";
}

@Extends(Animal.class)
@Animal(fluffy = true)
@interface Pet {
    String name();
}

@Extends(Pet.class)
@interface Cat {
    @AliasFor("name")
    String value();
}

@Extends(Pet.class)
@interface Dog {
    String name();
}

@interface Rat {
    @AliasFor(target = Animal.class, value = "name")
    String value();
}

@Cat("Tom")
class MyClass {
    @Dog(name = "Spike")
    @Rat("Jerry")
    public void foo() {
    }
}

        Pet petAnnotation = AnnotationMagic.getOneAnnotationOnClassOrNull(MyClass.class, Pet.class);
        assertEquals("Tom", petAnnotation.name());
        assertTrue(AnnotationMagic.instanceOf(petAnnotation, Animal.class));

        Animal animalAnnotation = AnnotationMagic.getOneAnnotationOnClassOrNull(MyClass.class, Animal.class);
        assertTrue(animalAnnotation.fluffy());

        Method fooMethod = MyClass.class.getMethod("foo");
        List<Animal> animalAnnotations = AnnotationMagic.getAnnotationsOnMethod(fooMethod, Animal.class);
        assertEquals(Arrays.asList("Spike", "Jerry"), animalAnnotations.stream().map(Animal::name).collect(toList()));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.