[java] Java에 Annotation Inheritance와 같은 것이 있습니까?

주석을 탐색 중이며 일부 주석이 계층 구조를 갖는 것처럼 보이는 지점에 도달했습니다.

저는 주석을 사용하여 카드의 백그라운드에서 코드를 생성하고 있습니다. 카드 유형 (코드와 주석이 다름)이 다르지만 이름처럼 공통되는 특정 요소가 있습니다.

@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이 공통 기반을 확장하도록 시도했지만 작동하지 않습니다. 그게 가능할까요 아니면 디자인 문제일까요?



답변

불행하게도. 분명히 그것은 완전히로드하지 않고 클래스의 주석을 읽는 프로그램과 관련이 있습니다. Java에서 주석을 확장 할 수없는 이유는 무엇입니까?를 참조하십시오 .

그러나 유형은 해당 주석이 인 경우 수퍼 클래스의 주석을 상속합니다 @Inherited.

또한 상호 작용하는 데 이러한 메서드가 필요하지 않으면 클래스에 주석을 쌓을 수 있습니다.

@Move
@Page
public class myAwesomeClass {}

당신에게 효과가없는 이유가 있습니까?


답변

상속 대신 기본 주석으로 주석을 달 수 있습니다. 이것은 Spring 프레임 워크에서 사용됩니다 .

예를 들어

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

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

@Car
class Foo {
}

그런 다음 Spring의 AnnotationUtilsVehicle사용하여 클래스에 주석이 추가되었는지 확인할 수 있습니다 .

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에서 발생하는 케이스를 검색 할 수있을만큼 강력합니다.


답변

주석 주석에 대한 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을 활성화해야합니다.


답변

동일한 질문이있을 때 개발 한 라이브러리 인 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()));


답변