我正在探索注释,并且发现某些注释似乎在它们之间具有层次结构。
我正在使用注释在后台为卡片生成代码。存在不同的卡类型(因此不同的代码和注释)但是在它们之间存在某些共同的元素,如名称。
@Target(value = {ElementType.TYPE})
public @interface Move extends Page{
String method1();
String method2();
}
这将是常见的注释:
@Target(value = {ElementType.TYPE})
public @interface Page{
String method3();
}
在上面的示例中,我希望Move继承方法3但是我收到一条警告,说扩展对注释无效。我试图让Annotation扩展一个共同的基础,但这不起作用。这甚至可能还是只是一个设计问题?
答案 0 :(得分:66)
不幸的是,没有。显然它与程序有关,这些程序读取类上的注释而不会一直加载它们。见Why is not possible to extend annotations in Java?
但是,如果这些注释为@Inherited
,则类型会继承其超类的注释。
此外,除非您需要这些方法进行交互,否则您只需在类上堆叠注释:
@Move
@Page
public class myAwesomeClass {}
有什么理由对你不起作用吗?
答案 1 :(得分:51)
您可以使用基本注释而不是继承来注释注释。这是used in Spring framework。
举个例子
@Target(value = {ElementType.ANNOTATION_TYPE})
public @interface Vehicle {
}
@Target(value = {ElementType.TYPE})
@Vehicle
public @interface Car {
}
@Car
class Foo {
}
然后,您可以使用Spring's AnnotationUtils检查某个类是否使用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中遇到的案例。
答案 2 :(得分: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
}
}
您基本上做的是获取方法中的所有注释以及您获取其类型的注释,并检查这些类型是否使用@Qualifier进行注释。您的注释也需要启用Target.Annotation_type才能使其正常工作。
答案 3 :(得分: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()));