Java中是否有类似注释继承的内容?


119

我正在探索批注,并得出了一些批注似乎在其中具有层次结构的观点。

我正在使用注释在Cards的后台生成代码。卡的类型不同(因此,代码和注释也不同),但是其中某些特定的元素(例如名称)是相同的。

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

这就是常见的注释:

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

在上面的示例中,我希望Move可以继承method3,但是会收到一条警告,指出extends对注释无效。我试图使Annotation扩展一个通用的基数,但这是行不通的。那有可能还是仅仅是设计问题?


3
注释继承似乎是基于注释创建DSL的必备条件。可惜不支持注释继承。
Ceki 2013年

2
我同意,这似乎是很自然的事情。特别是在理解Java上的继承之后,您会期望它适用于所有内容。
javydreamercsw

Answers:


76

抱歉不行。显然,它与读取类上的注释而不会完全加载它们的程序有关。请参见为什么无法在Java中扩展注释?

但是,如果类型为,则类型的确会继承其超类的注释@Inherited

另外,除非需要这些方法进行交互,否则可以将注解堆叠在类上:

@Move
@Page
public class myAwesomeClass {}

有什么原因对您不起作用吗?


1
那是我的想法,但我试图简化事情。也许将Common应用于抽象类可以解决问题……
javydreamercsw 2011年

1
是的,那看起来也很聪明。祝好运!
andronikus

67

您可以使用基本注释而不是继承注释您的注释。这在Spring框架中使用

举个例子

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

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

@Car
class Foo {
}

然后,您可以Vehicle使用Spring的AnnotationUtils检查类是否带有注释

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
请说明如何处理此类注释。
亚历山大·杜宾斯基

1
您可以使用Spring的AnnotationUtils.findAnnotation(..),请参阅:docs.spring.io/spring/docs/current/javadoc-api/org/...
rgrebski

2
当注释A用另一个注释B注释,并且我们用A注释类C时,将类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()));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.