如何访问方法参数的泛型类型参数上的注释?



假设我想使用反射检查以下类:

class Foo {
void bar(List<@Important String> b) {}
}

请注意,@Important注释不在参数本身上(然后我可以使用Method.getParameterAnnotations()),而是在其类型参数上(当注释声明为具有ElementType.TYPE_USE时允许这样做)。

有没有办法在 Java 11 中读取这样的注释?

不幸的是,反射API的这一部分很糟糕。基本类型没有必要的查询方法,也没有访客 API 等。因此,任何试图进行全面内省的代码都别无选择,只能执行大量instanceof检查,以处理所有可能的情况。

如果您事先知道该方法的类型应该是参数化类型,并且只想检查其第一个类型参数的注释,则可以更简单一些,忽略所有其他可能的情况:

import java.lang.annotation.*;
import java.lang.reflect.AnnotatedParameterizedType;
import java.lang.reflect.Method;
import java.util.*;
public class Main {
public static void main(String[] args) throws NoSuchMethodException {
Method m = Foo.class.getDeclaredMethod("bar", List.class);
var at  = m.getAnnotatedParameterTypes()[0];
var ata = ((AnnotatedParameterizedType)at).getAnnotatedActualTypeArguments()[0];
// get all annotations
for(var a: ata.getAnnotations()) {
System.out.println(a);
}
// or check the presence of a known annotation
System.out.println(ata.getAnnotation(Important.class) != null);
}
class Foo {
void bar(List<@Important String> b) {}
}
}

关于 Ideone 的演示

@Important()
true

TL;DR — 请参阅此答案,讨论类型参数、类型变量和类型参数之间的细微差别


冗长版

">...请注意,@Important注释是...在其类型参数上...">

在您的Foo声明中...

class Foo {
void bar(List<@Important String> b) {}
}

String不是类型参数。它也不是类型变量。在您的代码段中String有一个类型参数

虽然我最初说ReferenceType类型的参数不能有注释(事实证明它们可以),但我将这些 JLS 作品留在这里让我保持谦虚......

4.5.1. 参数化类型的类型参数

Type 参数可以是引用类型,也可以是通配符。通配符很有用 在只需要有关类型参数的部分知识的情况下。

TypeArguments:
< TypeArgumentList >

TypeArgumentList:
TypeArgument{, TypeArgument}

TypeArgument:
<<em>ReferenceTypebr/>Wildcard

Wildcard:
{Annotation}?[WildcardBounds]

WildcardBounds:
extendsReferenceType
superReferenceType

为了完整起见,JLS生产的类型参数...

4.4. 类型变量

>
类型变量是类、接口、方法和构造函数体中用作类型的非限定标识符。

类型变量是通过声明泛型类、接口、方法或构造函数的类型参数引入的...

TypeParameter:
{TypeParameterModifier} TypeIdentifier [TypeBound]:

TypeParameterModifier:
Annotation

...

虽然我从未在野外见过 -直到今天- 前面的JLS产品证实了你的代码片段中带注释的String类型参数确实是合法的Java。每天学习新东西!

最新更新