Search code examples
javareflectionannotations

How to get the annotation above the annotation


I added an annotation to the method, and there are other annotations in this annotation. When I try to get the annotation above by the method, unfortunately, the return is always null. I want to know why?

This is the method I defined

@ApiTest
public void add() {
}

This is the annotation I defined.

@ValueName("hello word")
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ApiTest {

}
////////////////////////////////////////////////////////
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ValueName {
  String value() default "";
}

The result always returns null when I try to get @ValueName

Class<?> testApi = Class.forName("com.huawei.netty.TestApi");
    Method add = testApi.getMethod("add", null);
    ApiTest apiTest = add.getDeclaredAnnotation(ApiTest.class);
    ValueName valueName = apiTest.getClass().getDeclaredAnnotation(ValueName.class);
    if (valueName != null) {
      System.out.println(valueName.annotationType());
    }

But this way can be obtained

Class<?> apiTest = Class.forName("com.huawei.netty.ApiTest");
    ValueName valueName = apiTest.getDeclaredAnnotation(ValueName.class);
    if (valueName != null) {
      System.out.println(valueName.value());
    }

Can I know why this is?


Solution

  • You should be using Annotation#annotationType() to get the class of the annotation instance, rather than Object#getClass(). The latter method is not returning the class you think it is. Try the following:

    MetaAnnotation.java

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface MetaAnnotation {
    
        String value();
    
    }
    

    CustomAnnotation.java

    @MetaAnnotation("Hello, World!")
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface CustomAnnotation {}
    

    Main.java

    @CustomAnnotation
    public final class Main {
    
        public static void main(String[] args) {
            CustomAnnotation ca = Main.class.getAnnotation(CustomAnnotation.class);
            MetaAnnotation   ma = ca.annotationType().getAnnotation(MetaAnnotation.class);
    
            System.out.println("CustomAnnotation#getClass()       = " + ca.getClass());
            System.out.println("CustomAnnotation#annotationType() = " + ca.annotationType());
            System.out.println("MetaAnnotation#value()            = " + ma.value());
        }
    
    }
    

    When I run the above using OpenJDK 12.0.1, I get the following output:

    CustomAnnotation#getClass()       = class com.sun.proxy.$Proxy1
    CustomAnnotation#annotationType() = interface CustomAnnotation
    MetaAnnotation#value()            = Hello, World!
    

    As you can see, the class of the annotation instance is a proxy class which would not have the annotation you're querying for.