简体   繁体   English

java中有没有像注解继承这样的东西?

[英]Is there something like Annotation Inheritance in java?

I'm exploring annotations and came to a point where some annotations seems to have a hierarchy among them.我正在探索注释,并发现一些注释之间似乎有层次结构。

I'm using annotations to generate code in the background for Cards.我正在使用注释在后台为卡片生成代码。 There are different Card types (thus different code and annotations) but there are certain elements that are common among them like a name.有不同的卡片类型(因此有不同的代码和注释),但它们之间有一些共同的元素,如名称。

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

And this would be the common Annotation:这将是常见的注释:

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

In the example above I would expect Move to inherit method3 but I get a warning saying that extends is not valid with annotations.在上面的示例中,我希望 Move 继承 method3,但我收到一条警告,指出 extends 对注释无效。 I was trying to have an Annotation extends a common base one but that doesn't work.我试图让一个 Annotation 扩展一个共同的基础,但这不起作用。 Is that even possible or is just a design issue?这是可能的还是只是一个设计问题?

Unfortunately, no.抱歉不行。 Apparently it has something to do with programs that read the annotations on a class without loading them all the way.显然,它与读取类上的注释而不完全加载它们的程序有关。 See Why is it not possible to extend annotations in Java?请参阅为什么不能在 Java 中扩展注释?

However, types do inherit the annotations of their superclass if those annotations are @Inherited .但是,如果这些注释是@Inherited ,则类型确实会继承其超类的注释。

Also, unless you need those methods to interact, you could just stack the annotations on your class:此外,除非您需要这些方法进行交互,否则您可以将注释堆叠在您的类上:

@Move
@Page
public class myAwesomeClass {}

Is there some reason that wouldn't work for you?有什么理由不适合你吗?

You can annotate your annotation with a base annotation instead of inheritance.您可以使用基本注释而不是继承来注释您的注释。 This is used in Spring framework .在 Spring 框架中使用

To give an example举个例子

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

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

@Car
class Foo {
}

You can then check if a class is annotated with Vehicle using Spring's AnnotationUtils :然后,您可以使用Spring 的 AnnotationUtils来检查类是否使用Vehicle进行了注释

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

This method is implemented as:该方法实现为:

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 also contains additional methods for searching for annotations on methods and other annotated elements. AnnotationUtils还包含用于搜索方法和其他带注释元素的注释的其他方法。 The Spring class is also powerful enough to search through bridged methods, proxies, and other corner-cases, particularly those encountered in Spring. Spring 类也足够强大,可以搜索桥接方法、代理和其他极端情况,尤其是在 Spring 中遇到的情况。

In addition to Grygoriys answer of annotating annotations.除了注释注释的 Grygoriys 答案。

You can check eg methods for containing a @Qualifier annotation (or an annotation annotated with @Qualifier ) by this loop:您可以通过此循环检查例如包含@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
    }
}

What you're basically doing, is to get all annotations present on the method and of those annotations you get their types and check those types if they're annotated with @Qualifier.您基本上要做的是获取方法上存在的所有注释,并且获取这些注释的类型并检查这些类型是否使用@Qualifier 进行注释。 Your annotation needs to be Target.Annotation_type enabled as well to get this working.您的注释也需要启用 Target.Annotation_type 才能使其正常工作。

Check out https://github.com/blindpirate/annotation-magic , which is a library I developed when I had the same question.查看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()));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM