繁体   English   中英

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

[英]How to get type annotations & attribute values for VariableElement with Java8?

请考虑以下代码:

public class SimpleTest {

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

使用最新的JDK8 API进行注释处理,如何从VariableElement访问注释列表( @JSON@ Frzen@Enumerated )及其相应的属性( @Enumerated的值和测试)?

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

我尝试过很多技巧,比如mapElm.getTypeArguments().get(0) for @Json Integer但是我从来没有成功地抓住注释@JSON ......

编辑 :通过访问JDK的内部类,我可以访问这些注释,但它是如此hacky和敏感的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 ),我可以使用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编译器不兼容。

我想在使用与ECJ编译器兼容的可用Element API之前,我将不得不等待JDK 9

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

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

获得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的。

必须使用@Retention(RetentionPolicy.RUNTIME)修饰@JSON,以便可以使用Reflection。

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

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

请参阅AnnotatedParameterizedType

暂无
暂无

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

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