当前位置: 首页 > 知识库问答 >
问题:

如何获取类型注释

杜俊楚
2023-03-14

考虑下面的代码:

public class SimpleTest {

    private Map<@JSON Integer,Map<@Frozen Integer,@Enumerated(value = Enumerated.Encoding.NAME, test = "123") String>> map;
}

使用用于注释处理的最新JDK8 API,如何访问注释列表(@JSON,@freezed)

final VariableElement mapElm = els.stream().filter(x -> x.getSimpleName().contentEquals("map")).findFirst().get();
???
???

我尝试过很多技巧,比如mapElm。getTypeArguments()。获取@Json整数的(0),但我从未成功获得@Json注释。。。

编辑:通过访问JDK的内部类,我可以访问那个些注释,但它对impl更改非常敏感,所以我想知道是否有更好的方法

public static class SimpleEntityCodecFactoryTest {

    private Map<@JSON Integer,Map<@Frozen Integer,@Enumerated(value = Enumerated.Encoding.NAME, test = "123") String>> map;
}

final TypeElement typeElement = elementUtils.getTypeElement(SimpleEntityCodecFactoryTest.class.getCanonicalName());
final List<VariableElement> els = ElementFilter.fieldsIn(typeElement.getEnclosedElements());

final VariableElement mapElt = els.stream().filter(x -> x.getSimpleName().contentEquals("map")).findFirst().get();
final com.sun.tools.javac.util.List<Attribute.TypeCompound> typeAttributes = ((Symbol.VarSymbol) mapElt).getMetadata().getTypeAttributes();
for (Attribute.TypeCompound typeAttribute : typeAttributes) {
    final DeclaredType annotationType = typeAttribute.getAnnotationType();
    System.out.println(format("Accessing annotation '%s' at location : %s",annotationType.toString(),typeAttribute.getPosition().location));
    for (Map.Entry<Symbol.MethodSymbol,Attribute> entry : typeAttribute.getElementValues().entrySet()) {
        final Symbol.MethodSymbol methodSymbol = entry.getKey();
        final Attribute attribute = entry.getValue();
        System.out.println(format("Attribute '%s' for annotation '%s' : %s", methodSymbol.name, annotationType.toString(), attribute.toString()));
    }
}    

输出显示:

Accessing annotation 'info.archinnov.achilles.annotations.JSON' at location : TYPE_ARGUMENT(0)
Accessing annotation 'info.archinnov.achilles.annotations.Frozen' at location : TYPE_ARGUMENT(1),TYPE_ARGUMENT(0)
Accessing annotation 'info.archinnov.achilles.annotations.Enumerated' at location : TYPE_ARGUMENT(1),TYPE_ARGUMENT(1)
Attribute 'value' for annotation 'info.archinnov.achilles.annotations.Enumerated' : info.archinnov.achilles.annotations.Enumerated.Encoding.NAME
Attribute 'test' for annotation 'info.archinnov.achilles.annotations.Enumerated' : "123"

上面的代码在IntelliJ中运行良好,但这是因为脏类型转换((Symbol.VarSymbol)mapElt)。getMetadata(),它正在使用Oracle JDK,但在使用Eclipse编译器时失败得很惨。

现在,除了脏类型转换之外,我找不到任何其他解决方案来访问泛型类型中的注释。任何想法都欢迎

解决方案:

多亏了Werner(wmdietl),我可以使用树API而不是元素或TypeMirror访问嵌套注释

然而,我非常困惑,因为一旦我到达那个里,就不可能将树的任何子类转换回元素或类型镜像(我真正的目标)。

我所有的注释处理都使用了大量的Java语言(https://github.com/square/javapoet)生成干净的源代码,这个框架只处理TypeMirror,而不是Tree

在https://github.com/typetools/checker-framework/blob/master/javacutil/src/org/checkerframework/javacutil/TreeUtils.java类,有一些方法可以将树转换回元素,但它依赖于InternalUtils,我不能使用它,因为它与EclipseECJ编译器不兼容。

我想我必须等到JDK9之后才能有一个与ECJ编译器兼容的可用元素API

编辑:为了使类型注释适用于Eclipse编译器,我必须转换为内部编译器类,如下所示:https://github.com/doanduyhai/Achilles/blob/master/achilles-core/src/main/java/info/archinnov/achilles/internals/parser/AnnotationTree.java#L83-185年。这很难看,但在JDK9之前,这是目前唯一的方法。


共有2个答案

万俟华辉
2023-03-14

@JSON必须装饰有@保持(Retention策略。运行时间),以便可以使用反射。

AnnotatedParameterizedType mapField = (AnnotatedParameterizedType)SimpleTest.class.getDeclaredFields()[0].getAnnotatedType();
AnnotatedType integerType = mapField.getAnnotatedActualTypeArguments()[0];

System.out.println(integerType.getAnnotations()[0]);
// -> @JSON()

请参见AnnotatedParameterizedType

庄星汉
2023-03-14

您不应该查看元素(或符号),而是查看TypeMirror(javax.lang.model.type.TypeMirror)。您感兴趣的注释是类型使用注释,因此您无法通过元素访问它们(很容易,有黑客方法)。

一旦拥有了TypeMirror,就可以使用javax中的方法。朗。模型。AnnotatedConstruct查询所有或特定批注。

需要注意的另一个方面是:通常的注释处理在编译器的早期运行,并且可能没有设置所有类型。有关在代码归属后运行处理器的方法,请参阅https://github.com/typetools/checker-framework/blob/master/javacutil/src/org/checkerframework/javacutil/AbstractTypeProcessor.java。或者,您可以在com.sun.source.util.Plugin中使用新的插件机制,但这是OpenJDK特定的。

 类似资料:
  • 问题内容: 我创建了自己的注释类型,如下所示: 并将其附加到一个类上: 我试图通过反射来获得类注释,如下所示: 但它没有打印任何内容。我究竟做错了什么? 问题答案: 默认的保留策略是,默认情况下,注释信息在运行时不保留: 批注由编译器记录在类文件中,但VM在运行时无需保留。这是默认行为。 而是使用: 注释将由编译器记录在类文件中,并在运行时由VM保留,因此可以通过反射方式读取它们。 …您使用met

  • 问题内容: 我在网上看到的解决方案很有意义;如果知道变量的类型,那么就知道其值的类型。Java就是这样。但是,如果我有这样的继承类系统… 并以这种方式创建对象… 有没有一种方法可以获取FirstPQ 的 类型 ,以便可以在强制转换中使用它,以便可以访问类的独占方法?也许与此类似? 问题答案: 您有几种选择。 您可以使用反射 你可以用 您可以使用访客模式 对于这些示例,我们将尝试查找此变量的类型:

  • 问题内容: 通常,我见过人们像这样使用类文字: 但是,如果类型是通用类型,例如List,该怎么办?这可以正常工作,但由于应将List参数化,因此发出警告: 那么为什么不添加一个<?>呢?好吧,这会导致类型不匹配错误: 我想像这样的事情会起作用,但这只是一个普通的语法错误: 如何获得Class >静态信息,例如使用类文字? 我可以使用,以摆脱在第一个例子中所造成的非参数使用列表,警告的,但我宁愿不要

  • 问题内容: 我有一些类型的非变量(例如)。问题是:如何获取与变量引用的枚举常量相关的注释? 问题答案: 正如我已经提供的: 要更清楚: 在这种情况下,我们无需知道的真实类。

  • 我正在与Avro合作,我有一个通用记录。我想从中提取clientId、deviceName、holder。在Avro模式中,

  • 问题:我想知道是否可以从DocumentFilter获取JTextfield类型 我读过java文档,搜索了很多,但没有找到任何信息。 需要:我在两个JTextfields上设置了相同的DocumentFilter。当事件发生时,在DocumentFilter的“replace”方法中,我想知道哪个textfield导致了事件。 用例:我有大约15个文本字段(未来可能会增加),我希望对所有这些字段