如何获得类型注释&使用Java8的VariableElement的属性值? [英] How to get type annotations & attribute values for VariableElement with Java8?

查看:190
本文介绍了如何获得类型注释&使用Java8的VariableElement的属性值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

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 )?

With the latest JDK8 API for annotation processing, how can I access the list of annotations (@JSON, @Frozen & @Enumerated) and their corresponding attributes (value & test for @Enumerated) from the VariableElement ?

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

我尝试了很多技巧,比如 mapElm.getTypeArguments()。get (0)对于 @Json Integer 但是我从未成功地接触到注释 @JSON .. 。

I've tried many tricks, like mapElm.getTypeArguments().get(0) for the @Json Integer but I never succeed to get my hand on the annotation @JSON...

编辑:通过访问JDK的内部类,我可以访问这些注释,但它对于impl更改是如此hacky和敏感我想知道是否有更好的方法

Edit: By accessing internal classes of the JDK, I can have access to those annotations but it's so hacky and sensitive to impl change that I'm wondering whether there is a better way

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编译器中失败了斯特龙g>。

The above code is working fine in IntelliJ, but because of the dirty cast ((Symbol.VarSymbol) mapElt).getMetadata(), it is working with Oracle JDK but fails miserably with Eclipse compiler.

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

Right now, I don't find any other solution than the dirty cast to access annotations in generic types. Any idea is welcomed

解决方案:

感谢Werner( wmdietl ),我可以使用树API 而不是元素 TypeMirror

Thanks to Werner (wmdietl), I can access the nested annotations using the Tree API instead of Elements or TypeMirror

但是我很困难,因为一旦到达那里,就无法将的任何子类转换回元素 TypeMirror (我的真实目标)。

However I'm quite stuck because once I get there, it is not possible to convert any subclass of Tree back to Element or TypeMirror (my real target).

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

All of my annotation processing is using heavily JavaPoet (https://github.com/square/javapoet) to generate clean source code and this framework only handles TypeMirror, not Tree

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

In the https://github.com/typetools/checker-framework/blob/master/javacutil/src/org/checkerframework/javacutil/TreeUtils.java class, there are some methods to convert Tree back to Element but it is relying on InternalUtils, which I can't use because it won't be compatible with Eclipse ECJ compiler.

我想在使用与ECJ编译器兼容的可用Element API之前我必须等待JDK 9

I guess I will have to wait for JDK 9 before having an usable Element API that will be compatible with ECJ compiler

编辑:使类型annotati在 Eclipse编译器的工作中,我不得不像这里一样转换到内部编译器类: https://github.com/doanduyhai/Achilles/blob/master/achilles-core/src /main/java/info/archinnov/achilles/internals/parser/AnnotationTree.java#L83-L85 。这很丑,但这是现在唯一的方法,直到JDK9。

Edit: To make the type annotation work for Eclipse Compiler, I had to cast to internal compiler classes like here: https://github.com/doanduyhai/Achilles/blob/master/achilles-core/src/main/java/info/archinnov/achilles/internals/parser/AnnotationTree.java#L83-L85. It's ugly but that is the only way for now until JDK9.

推荐答案

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

You shouldn't look at the Element (or Symbol), but at the TypeMirror (javax.lang.model.type.TypeMirror). The annotations you are interested in are type use annotations, so you can't access them (easily, there are hacky ways) through the Element.

一次你有 TypeMirror ,你可以使用 javax.lang.model.AnnotatedConstruct 中的方法来查询所有或特定的注释。

Once you have the TypeMirror, you can use the methods in javax.lang.model.AnnotatedConstruct to query for all or particular annotations.

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

Another aspect to be aware of: usual annotation processing runs early in the compiler and not all types might have been set. See https://github.com/typetools/checker-framework/blob/master/javacutil/src/org/checkerframework/javacutil/AbstractTypeProcessor.java for a way to run your processor after code attribution. Alternatively, you can use the new "plugin" mechanism in com.sun.source.util.Plugin, but that is OpenJDK specific.

这篇关于如何获得类型注释&amp;使用Java8的VariableElement的属性值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆