Java 中有类似于注释继承的东西吗?

我正在研究注释,发现一些注释似乎在它们之间有层次结构。

我使用注释为 Cards 在后台生成代码。有不同的 Card 类型(因此有不同的代码和注释) ,但是有一些元素是通用的,比如名称。

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

这就是常见的注释:

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

在上面的例子中,我希望 Move 继承 method3,但是我得到一个警告,说 Extended 对注释无效。我尝试用一个注释扩展一个通用的基本注释,但是没有用。这可能吗,还是只是设计问题?

119681 次浏览

很不幸,没有。显然,它与那些读取类上的注释而不必一直加载它们的程序有关。参见 为什么在 Java 中不可能扩展注释?

但是,如果这些注释是 @Inherited,那么类型确实继承了它们的超类的注释。

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

@Move
@Page
public class myAwesomeClass {}

有什么理由不适合你吗?

您可以使用基础注释而不是继承来注释您的注释。

举个例子

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


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


@Car
class Foo {
}

然后,您可以使用 Spring 的注释工具检查类是否使用 Vehicle进行了注释:

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 中遇到的情况。

除了格里高利对注释的回答。

你可以通过这个循环来检查方法是否包含一个 @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。启用了注释 _ type 以使其正常工作。

看看 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()));