java - 如何使用 Java8 获取 VariableElement 的类型注释和属性值?

标签 java annotation-processing

考虑以下代码:

public class SimpleTest {

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

使用最新的 JDK8 API 进行注解处理,如何访问注解列表(@JSON@Frozen & @Enumerated ) 及其对应的属性(@Enumerated 的值和测试)来自 VariableElement ?

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

我尝试了很多技巧,比如 mapElm.getTypeArguments().get(0) 用于 @Json Integer 但我从来没有成功地掌握注释 @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() 的脏转换,它与 < strong>Oracle JDK 但在使用 Eclipse 编译器 时惨遭失败。

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

解决方案:

感谢 Werner (wmdietl),我可以使用 Tree API 而不是 ElementsTypeMirror< 访问嵌套注释/强>

但是我很困惑,因为一旦我到达那里,就不可能将 Tree 的任何子类转换回 ElementTypeMirror(我真正的目标)。

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

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

我想我必须等待 JDK 9 才能拥有与 ECJ 编译器兼容的可用 Element API

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

最佳答案

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

一旦您拥有了 TypeMirror,您就可以使用 javax.lang.model.AnnotatedConstruct 中的方法来查询所有或特定的注释。

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

关于java - 如何使用 Java8 获取 VariableElement 的类型注释和属性值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31842774/

相关文章:

Java:回文,没有获得最大数

java - 如何匹配正则表达式中的最大数字

java - Android BroadcastReceiver onReceive 在 MainActivity 中更新 TextView

java - 准备好的查询的奇怪错误不是 SELECT_LONG 类型

java - 实例化一个带有某些注释的类

Java 注释处理器 - 带注释的 Kotlin 类单元测试

java - 如何以编程方式获取电话号码?

java - 如何在 APT 中访问 @XmlElement 值?

java - Lombok 注释在测试中未处理 - Bazel

java - Kotlin 不识别 Java 保留关键字