如何解析泛型中的 Java 注解?
How to parse Java annotation in generic type?
我有这样的注释:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
public @interface NotNull {}
还有 class:
class Main{
List<@NotNull String> list;
}
我应该如何使用反射解析此注释 API?
注释显示在 泛型部分中。这立即意味着两件事:
如果类型位于不是签名一部分的位置(因此,局部变量声明、强制转换或 new Foo<X>()
中的 X 等 - 那么它就这样消失了,泛型在这种情况下被抹掉了。根本没有办法引用它,在运行时你再也看不到它了。
如果类型是签名的部分(它是字段的类型,方法的return类型,类型一个参数,或者你 extends
或 implements
) 的东西,然后在 运行 时保留它,但是,获取这些东西的所有常用方法,例如 someJLReflectFieldInstance.getType()
,总是 return 一个 java.lang.Class
实例,泛型也从这些实例中删除,所以你不能使用这些方法。
如果您在 1 号船上,答案立即结束:不可能。
如果您在 2 号船上,这是可能的。首先,找到 getGenericType()
方法 - 一种变体方法,它也是 return 您想要的类型,但作为 Type
而不是 Class
。对于 j.l.reflect.Field
,该方法是 getGenericType()
。方法 return 类型、参数类型等存在类似的方法。然后意识到这仍然不够——这让你得到了 <>
中的内容,但去掉了所有注释。继续寻找,您会找到真正的赢家。对于j.l.r.Field
,即getAnnotatedType
.
你现在有一个 AnnotatedType
,它看起来几乎完全没用:它几乎没有任何方法。这是一个包罗万象的标记式界面,因为对于 java 中的类型有不同的想法。 ?
是这个意义上的类型,因为它可以出现在类型出现的地方:List<?>
。 ? extends Map<?, Set<String>>
也是如此。 T
也是,String
也是,int[]
也是,double
也是。而且几乎都可以标注。
通常的解决方案是转换和 instanceof
检查。 List<@NonNull String>
之类的东西是 java.lang.reflect.AnnotatedParameterizedType
。因此,让我们投射并继续。这个接口有getAnnotatedActualTypeArguments()
方法,return又是那个无用AnnotatedType
的数组:合适;毕竟,它可能是 List<?>
、List<String>
、List<T>
、List<? extends Stuff>
等等。
@NonNull String
将是 java.lang.reflect.AnnotatedType
.
的实例
让我们把它们放在一起。把它扔进一个文件,编译它,然后 运行 它:
import java.lang.annotation.*;
import java.util.List;
import java.lang.reflect.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
@interface NonNull {}
class Test {
List<@NonNull String> example;
public static void main(String[] args) throws Exception {
Field f = Test.class.getDeclaredField("example");
AnnotatedParameterizedType listType =
(AnnotatedParameterizedType) f.getAnnotatedType();
AnnotatedType annType = (AnnotatedType)
listType.getAnnotatedActualTypeArguments()[0];
for (Annotation ann : annType.getAnnotations()) {
System.out.println("Annotation found: " + ann);
}
}
}
javac Test.java; java Test
> Annotation found: @NonNull()
注意:如果您知道自己在寻找什么,上面的内容还不错,但是如果您尝试处理可能类型种类繁多的数组(呵呵),您很快就会 运行变成一大堆混乱的代码。我不直接知道图书馆可以提供帮助,但您可能想调查一下或写点东西;为这些东西设置访问者模式并不难。
我有这样的注释:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
public @interface NotNull {}
还有 class:
class Main{
List<@NotNull String> list;
}
我应该如何使用反射解析此注释 API?
注释显示在 泛型部分中。这立即意味着两件事:
如果类型位于不是签名一部分的位置(因此,局部变量声明、强制转换或
new Foo<X>()
中的 X 等 - 那么它就这样消失了,泛型在这种情况下被抹掉了。根本没有办法引用它,在运行时你再也看不到它了。如果类型是签名的部分(它是字段的类型,方法的return类型,类型一个参数,或者你
extends
或implements
) 的东西,然后在 运行 时保留它,但是,获取这些东西的所有常用方法,例如someJLReflectFieldInstance.getType()
,总是 return 一个java.lang.Class
实例,泛型也从这些实例中删除,所以你不能使用这些方法。
如果您在 1 号船上,答案立即结束:不可能。
如果您在 2 号船上,这是可能的。首先,找到 getGenericType()
方法 - 一种变体方法,它也是 return 您想要的类型,但作为 Type
而不是 Class
。对于 j.l.reflect.Field
,该方法是 getGenericType()
。方法 return 类型、参数类型等存在类似的方法。然后意识到这仍然不够——这让你得到了 <>
中的内容,但去掉了所有注释。继续寻找,您会找到真正的赢家。对于j.l.r.Field
,即getAnnotatedType
.
你现在有一个 AnnotatedType
,它看起来几乎完全没用:它几乎没有任何方法。这是一个包罗万象的标记式界面,因为对于 java 中的类型有不同的想法。 ?
是这个意义上的类型,因为它可以出现在类型出现的地方:List<?>
。 ? extends Map<?, Set<String>>
也是如此。 T
也是,String
也是,int[]
也是,double
也是。而且几乎都可以标注。
通常的解决方案是转换和 instanceof
检查。 List<@NonNull String>
之类的东西是 java.lang.reflect.AnnotatedParameterizedType
。因此,让我们投射并继续。这个接口有getAnnotatedActualTypeArguments()
方法,return又是那个无用AnnotatedType
的数组:合适;毕竟,它可能是 List<?>
、List<String>
、List<T>
、List<? extends Stuff>
等等。
@NonNull String
将是 java.lang.reflect.AnnotatedType
.
让我们把它们放在一起。把它扔进一个文件,编译它,然后 运行 它:
import java.lang.annotation.*;
import java.util.List;
import java.lang.reflect.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
@interface NonNull {}
class Test {
List<@NonNull String> example;
public static void main(String[] args) throws Exception {
Field f = Test.class.getDeclaredField("example");
AnnotatedParameterizedType listType =
(AnnotatedParameterizedType) f.getAnnotatedType();
AnnotatedType annType = (AnnotatedType)
listType.getAnnotatedActualTypeArguments()[0];
for (Annotation ann : annType.getAnnotations()) {
System.out.println("Annotation found: " + ann);
}
}
}
javac Test.java; java Test
> Annotation found: @NonNull()
注意:如果您知道自己在寻找什么,上面的内容还不错,但是如果您尝试处理可能类型种类繁多的数组(呵呵),您很快就会 运行变成一大堆混乱的代码。我不直接知道图书馆可以提供帮助,但您可能想调查一下或写点东西;为这些东西设置访问者模式并不难。