如何访问方法参数的泛型类型参数上的注释?
How to access an annotation on a generic type parameter of a method argument?
假设我想使用反射检查以下 class:
class Foo {
void bar(List<@Important String> b) {}
}
请注意,@Important
注释在参数本身上是 而不是 (然后我可以使用 Method.getParameterAnnotations()
),但在它的类型参数上(这是当注释被声明为 ElementType.TYPE_USE
).
时允许
有没有办法在 Java 11 中读取此类注释?
TL;DR — 请参阅此答案 discussing the subtle differences type parameters, type variables and type arguments.
long-winded版本
„…Note that the @Important
annotation is…on its type parameter…“
在你的Foo
声明中…
class Foo {
void bar(List<@Important String> b) {}
}
…String
不是 type parameter. Nor is it a type variable. In your snippet there String
is a type argument.
虽然我在 saying originally that ReferenceType
type arguments can't have annotations (turns out they can 上得到纠正)我会把这些 JLS 作品留在这里让我保持谦虚 …
4.5.1. Type Arguments of Parameterized Types
Type arguments may be either reference types or wildcards. Wildcards are useful
in situations where only partial knowledge about the type parameter is required.
TypeArguments:
< TypeArgumentList >
TypeArgumentList:
TypeArgument
{, TypeArgument}
TypeArgument:
ReferenceType
Wildcard
Wildcard:
{Annotation}
?
[WildcardBounds]
WildcardBounds:
extends
ReferenceType
super
ReferenceType
为了完整性,类型参数…
的JLS生产
4.4. Type Variables
A type variable is an unqualified identifier used as a type in class, interface, method, and constructor bodies.
A type variable is introduced by the declaration of a type parameter of a generic class, interface, method, or constructor…
TypeParameter:
{TypeParameterModifier} TypeIdentifier [TypeBound]:
TypeParameterModifier:
Annotation
…
尽管我从未在野外见过它们 — 直到今天 — 前面的 JLS 产品证实了带注释的 String
type argument 在你的片段中确实是合法的 Java。每天学点新东西!
不幸的是,反射的这一部分 API 太可怕了。基本类型没有必要的查询方法,也没有 Visitor 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) {}
}
}
@Important()
true
假设我想使用反射检查以下 class:
class Foo {
void bar(List<@Important String> b) {}
}
请注意,@Important
注释在参数本身上是 而不是 (然后我可以使用 Method.getParameterAnnotations()
),但在它的类型参数上(这是当注释被声明为 ElementType.TYPE_USE
).
有没有办法在 Java 11 中读取此类注释?
TL;DR — 请参阅此答案 discussing the subtle differences type parameters, type variables and type arguments.
long-winded版本
„…Note that the
@Important
annotation is…on its type parameter…“
在你的Foo
声明中…
class Foo {
void bar(List<@Important String> b) {}
}
…String
不是 type parameter. Nor is it a type variable. In your snippet there String
is a type argument.
虽然我在 saying originally that ReferenceType
type arguments can't have annotations (turns out they can 上得到纠正)我会把这些 JLS 作品留在这里让我保持谦虚 …
4.5.1. Type Arguments of Parameterized Types
Type arguments may be either reference types or wildcards. Wildcards are useful in situations where only partial knowledge about the type parameter is required.
TypeArguments:
< TypeArgumentList >
TypeArgumentList:
TypeArgument
{, TypeArgument}
TypeArgument:
ReferenceType
Wildcard
Wildcard:
{Annotation}
?
[WildcardBounds]
WildcardBounds:
extends
ReferenceType
super
ReferenceType
为了完整性,类型参数…
的JLS生产4.4. Type Variables
A type variable is an unqualified identifier used as a type in class, interface, method, and constructor bodies.
A type variable is introduced by the declaration of a type parameter of a generic class, interface, method, or constructor…
TypeParameter:
{TypeParameterModifier} TypeIdentifier [TypeBound]:
TypeParameterModifier:
Annotation
…
尽管我从未在野外见过它们 — 直到今天 — 前面的 JLS 产品证实了带注释的 String
type argument 在你的片段中确实是合法的 Java。每天学点新东西!
不幸的是,反射的这一部分 API 太可怕了。基本类型没有必要的查询方法,也没有 Visitor 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) {}
}
}
@Important()
true