TYPE_USE annotations get lost when type is nested, generic interface

Tillerino :

It appears that TYPE_USE annotations cannot be accessed through reflection when the annotated type is a nested, generic interface.

Please observe the following example:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;

public class LostAnnotation {
  @Retention(RetentionPolicy.RUNTIME)
  @Target(ElementType.TYPE_USE)
  public @interface SomeTypeAnnotation {
  }

  @SomeTypeAnnotation Map<String, String> map;
  @SomeTypeAnnotation Entry<String, String> entry;

  public static @SomeTypeAnnotation Entry<String, String> someMethod(
      @SomeTypeAnnotation Map<String, String> map,
      @SomeTypeAnnotation Entry<String, String> entry) {
    return null;
  }

  public static void main(String[] args) throws Exception {
    Class<LostAnnotation> clazz = LostAnnotation.class;
    Method method = clazz.getMethod("someMethod", Map.class, Entry.class);
    AnnotatedType[] types = method.getAnnotatedParameterTypes();

    print("map field", clazz.getDeclaredField("map").getAnnotatedType());
    print("map parameter", types[0]);

    print("entry field", clazz.getDeclaredField("entry").getAnnotatedType());
    print("entry parameter", types[1]);
    print("entry return type", method.getAnnotatedReturnType());
  }

  static void print(String title, AnnotatedType type) {
    System.out.printf("%s: %s%n", title, Arrays.asList(type.getAnnotations()));
  }
}

The expected output of the above code is

map field: [@LostAnnotation$SomeTypeAnnotation()]
map parameter: [@LostAnnotation$SomeTypeAnnotation()]
entry field: [@LostAnnotation$SomeTypeAnnotation()]
entry parameter: [@LostAnnotation$SomeTypeAnnotation()]
entry return type: [@LostAnnotation$SomeTypeAnnotation()]

However, the actual output of the above code is

map field: [@LostAnnotation$SomeTypeAnnotation()]
map parameter: [@LostAnnotation$SomeTypeAnnotation()]
entry field: []
entry parameter: []
entry return type: []

The annotation is correctly retrieved from every usage of the Map interface. However, on every usage of the Entry interface, be it field, return type or parameter, the annotation is lost. The only explanation that I have for this is that the Entry interface is nested inside the Map interface.

I ran the above example on the newest oracle JDK (8u121) on win64. Am I doing something wrong or could this be a bug?

My Annotation is nested for readability. Making it a top-level interface doesn't change anything.

rdlopes :

This has been already spotted in SO: Why annotation on generic type argument is not visible for nested type?

Answer is bug has been submitted but in lower priority as those cases do not appear frequently.

Still, you can use ByteBuddy to parse the bytecode and retrieve the annotated type.

ASM works too, from my experience, and I suspect any bytecode parser would work around this bug.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=457045&siteId=1