繁体   English   中英

如何解析泛型类型的 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 解析这个注释?

注释显示generics 部分中。 这立即意味着两件事:

  1. 如果类型位于不属于签名的位置(因此,局部变量声明或强制转换,或new Foo<X>()中的 X 等 - 那么它就消失了,generics 被删除在这种情况下。根本没有办法引用它,在运行时你再也看不到它了。

  2. 如果类型签名的一部分(它是字段的类型、方法的返回类型、参数的类型或您extendsimplements的东西),那么它会在运行时保留,但是,所有常见的获取这些东西的方法,例如someJLReflectFieldInstance.getType() ,总是返回一个java.lang.Class实例和 generics 实例,所以你也可以使用这些方法。

如果你在#1 船上,答案马上就结束了:不可能

如果你在#2 船上,这是可能的。 首先,找到getGenericType()方法 - 一种变体方法,它也返回您想要的类型,但作为Type而不是Class 对于jlreflect.Field ,该方法是getGenericType() 类似的方法存在于方法返回类型、参数类型等。 然后意识到这还不够——这让你得到了<>中的东西,但是去掉了所有的注释。 继续寻找,你会找到真正的赢家。 对于jlr.Field ,即getAnnotatedType

你现在有一个AnnotatedType ,它看起来几乎完全没用:它几乎没有任何方法。 这是一个包罗万象的标记式界面,因为对于 java 中的类型有不同的想法。 ? 在这个意义上是一种类型,因为它可以出现在类型出现的地方: List<?> 也是? extends Map<?, Set<String>> ? extends Map<?, Set<String>> T也是如此, String也是如此, int[]也是如此, double也是如此。 它们几乎都可以被注释。

通常的解决方案是强制转换和instanceof检查。 List<@NonNull String>类的东西是java.lang.reflect.AnnotatedParameterizedType 所以让我们投射并继续。 这个接口有getAnnotatedActualTypeArguments()方法,它再次返回那个无用的AnnotatedType的数组: 毕竟,它可能是List<?>List<String>List<T>List<? extends Stuff> 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()

注意:如果你知道你在找什么,上面的内容还不错,但是如果你试图处理大量可能的类型类型(呵呵),你很快就会遇到一大堆混乱的代码。 我不直接知道图书馆可以提供帮助,但您可能想研究它或写一些东西; 为这些东西设置访问者模式并不难。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM