【问题标题】:How to get TYPE_USE annotations on a generic bound如何在通用绑定上获取 TYPE_USE 注释
【发布时间】:2023-03-28 22:05:01
【问题描述】:

我有这种情况:

public class SomeClass<T> {
    public <@A1 S extends @A2 T> @A3 S myMethod() { ...}
}

我正在尝试在绑定的T 上获取@A2 注释。
这就是我所看到的,假设myMethodSomeClass.class.getDeclaredMethod("myMethod")。为了便于阅读,移除了类型转换。

  • myMethod.getGenericReturnType().getAnnotations() 返回 @A1(我猜是预期的)
  • myMethod.getGenericReturnType().getBounds()[0].getAnnotations() 返回 nothing(??不应该是 @A2 吗??)
  • myMethod.getAnnotatedReturnType().getAnnotations() 返回 @A3(我猜是预期的)
  • myMethod.getAnnotatedReturnType().getAnnotatedBounds()[0].getAnnotations() 返回 nothing(我猜是例外)

似乎@A2 迷路了……这听起来不太明智。我做错了什么还是这确实是一些奇怪的行为?

更新: 这确实是一个 JDK 错误,我报告了它并被接受为 JDK-8191466

【问题讨论】:

  • 实际上从来不需要这样做......但是一个非常好的问题!

标签: java generics reflection java-8 annotations


【解决方案1】:

所有类型注释都可以通过AnnotatedType层次结构检索,除了TypeVariable,它的注释可以通过AnnotatedTypeVariable.getType()检索,这将是TypeVariable的一个实例,它现在扩展了AnnotatedElement,碰巧与Method.getGenericReturnType()返回的对象一致。

因此您可以检索所有信息,例如

AnnotatedType art = myMethod.getAnnotatedReturnType();
System.out.print(
    Arrays.toString(art.getAnnotations())+" "+art.getType().getTypeName()+" -> ");
final boolean typeVariable = art instanceof AnnotatedTypeVariable;
if (typeVariable) System.out.print('<');
System.out.print(Arrays.toString(((AnnotatedElement)art.getType()).getAnnotations()) + " ");
System.out.print(art.getType().getTypeName());
if (typeVariable) {
    AnnotatedTypeVariable atv = (AnnotatedTypeVariable)art;
    AnnotatedType[] annotatedBounds = atv.getAnnotatedBounds();
    if (annotatedBounds.length > 0) {
        System.out.print(" extends ");
        for (AnnotatedType aBound: annotatedBounds) {
            System.out.print(Arrays.toString(aBound.getAnnotations()) + " ");
            System.out.print(aBound.getType().getTypeName() + ", ");
        }
    }
    System.out.println(">");
}

将打印

[@A3()] S -> <[@A1()] S extends [@A2()] T, >

当您对((AnnotatedTypeVariable)myMethod.getAnnotatedReturnType()) .getAnnotatedBounds()[0].getAnnotations() 的调用未提供@A2 时,您应该重新检查A2 是否确实具有@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE_USE)

当然,那是只处理您的特定方法的“简化”版本。

要处理所有可能的情况,您将需要更多的instanceofs,处理这些分离的类型层次结构TypeAnnotatedType,尤其是在处理带注释的参数化类型和带注释的泛型数组类型时。

如前所述,TypeVariable 不同,因为它扩展了AnnotatedElement 并且还具有getAnnotatedBounds() 方法。因此,在这种特定情况下,处理该方法的另一种方法是

List<TypeVariable<?>> typeParameters = Arrays.asList(myMethod.getTypeParameters());

for (TypeVariable<?> tv: typeParameters) {
    System.out.print("< "+Arrays.toString(tv.getAnnotations())+" "+tv.getName());
    AnnotatedType[] annotatedBounds = tv.getAnnotatedBounds();
    if (annotatedBounds.length > 0) {
        System.out.print(" extends ");
        for (AnnotatedType aBound: annotatedBounds) {
            System.out.print(Arrays.toString(aBound.getAnnotations()) + " ");
            System.out.print(aBound.getType().getTypeName() + ", ");
        }
    }
    System.out.print("> ");
}

AnnotatedType art = myMethod.getAnnotatedReturnType();
System.out.print(Arrays.toString(art.getAnnotations()) + " ");
int ix = typeParameters.indexOf(art.getType());
if (ix >= 0) System.out.print("[ref to type parameter #" + ix + "] ");
System.out.println(art.getType().getTypeName());

【讨论】:

  • 非常感谢(赞成)!但是......它让我意识到是什么让@A2 disappear 在我的例子中是 T 在我的示例中来自类定义(我修改了上面的代码以显示 SomeClass&lt;T&gt;包含myMethod)。现在,我明白这会改变情况,但必须仍然可以以某种方式检索注释......但似乎没有办法。您的代码无法恢复它,就像我的一样。
  • 在这种情况下,即使递归地应用AnnotatedTypeVariable 处理也无济于事。注释似乎丢失了。
  • 它的not the first bug在JDK8的注解处理中。我想知道JDK9的行为是否不同。
  • 至少,我可以验证编译后的类文件中是否存在信息。 Java 9 没有任何区别。
  • 我明白了。非常感谢您提供的额外信息!我会接受答案,因为我确信这是可以做到的。
猜你喜欢
  • 2015-02-12
  • 2017-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多