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

jav*_*csw 110 java inheritance annotations

我正在探索注释,并且发现某些注释似乎在它们之间具有层次结构.

我正在使用注释在后台为卡片生成代码.存在不同的卡类型(因此不同的代码和注释)但是在它们之间存在某些共同的元素,如名称.

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

这将是常见的注释:

@Target(value = {ElementType.TYPE})
public @interface Page{
 String method3();
}
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,我希望Move继承方法3但是我得到一个警告,说扩展对注释无效.我试图让Annotation扩展一个共同的基础,但这不起作用.这是可能的还是只是一个设计问题?

and*_*kus 72

很不幸的是,不行.显然它与程序有关,这些程序读取类上的注释而不会一直加载它们.请参阅为什么无法在Java中扩展注释?

但是,如果这些注释是类型,则类型会继承其超类的注释@Inherited.

此外,除非您需要这些方法进行交互,否则您只需在类上堆叠注释即可:

@Move
@Page
public class myAwesomeClass {}
Run Code Online (Sandbox Code Playgroud)

有什么理由对你不起作用吗?


Gry*_*har 56

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

举个例子

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

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

@Car
class Foo {
}
Run Code Online (Sandbox Code Playgroud)

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

Vehicle vehicleAnnotation = AnnotationUtils.findAnnotation (Foo.class, Vehicle.class);
boolean isAnnotated = vehicleAnnotation != null;
Run Code Online (Sandbox Code Playgroud)

该方法实现为:

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);
}
Run Code Online (Sandbox Code Playgroud)

AnnotationUtils还包含用于搜索方法和其他带注释元素的注释的其他方法.Spring类也足够强大,可以搜索桥接方法,代理和其他角落案例,特别是那些在Spring中遇到的案例.

  • 请提供有关如何处理此类注释的说明. (12认同)
  • 当注解 A 用另一个注解 B 进行注解,而我们用 A 对类 C 进行注解时,类 C 被视为同时注解了 A 和 B。这是 Spring 框架的特定行为—— AnnotationUtils.findAnnotation 发挥了作用这里 和 用于向上遍历以查找注释的注释。所以不要误会这是 Java 关于注解处理的默认行为。 (4认同)
  • 仅当您希望编写的注释具有“TYPE”或“ANNOTATION_TYPE”目标时,这才可能实现。 (2认同)

phi*_*ate 5

除了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
    }
}
Run Code Online (Sandbox Code Playgroud)

你基本上做的是获得方法上的所有注释和那些你得到类型的注释,并检查那些类型,如果它们用@Qualifier注释.您的注释需要启用Target.Annotation_type才能使其正常工作.

  • @AleksandrDubinsky:这只是一个更简单的实现,无需使用 Spring。它不会递归地查找带注释的注释,但我猜这通常不是必需的。我喜欢这个解决方案的简单性。 (2认同)

小智 5

查看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()));
Run Code Online (Sandbox Code Playgroud)