当类型是嵌套的通用接口时,TYPE_USE注释会丢失

时间:2017-02-28 15:27:18

标签: java reflection annotations

当带注释的类型是嵌套的通用接口时,似乎无法通过反射访问TYPE_USE注释。

请注意以下示例:

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

上述代码的预期输出

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

但是,上述代码的实际输出

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

Map接口的每次使用中正确检索注释。但是,在Entry接口的每次使用时,无论是字段,返回类型还是参数,注释都会丢失。我对此的唯一解释是Entry接口嵌套在 Map接口中。

我在win64上的最新oracle JDK(8u121)上运行了上面的例子。我做错了什么或者这可能是个错误吗?

我的注释是为了便于阅读而嵌套的。使其成为顶级界面并不会改变任何内容。

2 个答案:

答案 0 :(得分:5)

SO: Why annotation on generic type argument is not visible for nested type?

已经发现了这一点

答案是已提交错误,但优先级较低,因为这些情况不会经常出现。

但是,您仍然可以使用ByteBuddy来解析字节码并检索带注释的类型。

根据我的经验,

ASM也有效,我怀疑任何字节码解析器都可以解决这个错误。

答案 1 :(得分:0)

我不知道我是否算作可信来源(绝对不是官方来源),但IMO这是JDK中的一个错误或至少是一个缺点(未完全实现)。

你没有做错任何事 - 或者我们都错了,这仍然是可能的。

正如Bertrand Russell所说:

  

一个意见被广泛持有的事实并不是证据,无论它是多么荒谬。

- )