我正在尝试使用注释处理器和注释镜像读取注释中枚举的值,但我得到了null。我认为这与将Enum包装为VariableElement的AnnotationValue有关。 VariableElement的文档#getConstantValue()表示“如果这是一个初始化为编译时常量的最终字段,则返回此变量的值。”好的,但是final不是注释成员的有效修饰符。另外值得注意的是,我可以轻松阅读其他注释值,只需阅读Enums。
我做了一些调查,看起来AnnotationValue在运行时被实例化为Symbol.VarSymbol,但是Symbol.VarSymbol #getConstantValue()看起来应该只返回该对象。
最后,如果我在AnnotationValue上执行toString(),我会得到正确的值。
注释:
package annotation;
public @interface AnAnnotation
{
String value();
Behavior defaultBehavior() default Behavior.NEW;
public static enum Behavior
{
NEW, NULL;
}
}
我的处理器的一部分并嵌套在过多的循环中以获得正确的AnnotaionMirror:
Map<? extends ExecutableElement, ? extends AnnotationValue> annotationValues = elemUtils.getElementValuesWithDefaults(annotationMirror);
for (ExecutableElement method : annotationValues.keySet())
{
...
else if ("defaultBehavior".equals(method.getSimpleName().toString()))
{
defaultBehavior = (Behavior)( (VariableElement)annotationValues.get(method).getValue()).getConstantValue();
// This prints "NEW" or "NULL" correctly
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,annotationValues.get(method).toString());
// This prints null incorrectly (expect "NEW" or "NULL")
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, defaultBehavior + "");
}
...
}
编辑:处理器的更完整版本。
package annotation.processor;
import java.util.*;
import javax.annotation.processing.*;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import javax.lang.model.util.*;
import javax.tools.*;
import annotation.AnAnnotation;
import annotation.AnAnnotation.Behavior;
@SupportedAnnotationTypes("annotation.AnAnnotation")
public class AnAnnotationProcessor extends AbstractProcessor
{
Types typeUtils;
Elements elemUtils;
@Override
public void init(ProcessingEnvironment processingEnv)
{
super.init(processingEnv);
typeUtils = processingEnv.getTypeUtils();
elemUtils = processingEnv.getElementUtils();
}
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv)
{
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
"Entering AnnotationNullableClassProcessor");
/****** Iterate over all annotaions being processed (only AnAnnotation) ******/
for (TypeElement annotation : annotations)
{
/****** Iterate over all elements that are annotated with the annotation ******/
for (Element element : roundEnv.getElementsAnnotatedWith(annotation))
{
/****** Iterate over all the declared annotations of the element ******/
for (AnnotationMirror annotationMirror : element.getAnnotationMirrors())
{
final String annotationTypeName = annotationMirror.getAnnotationType().toString();
// Process annotations of type AnAnnotation
if (annotationTypeName.equals(AnAnnotation.class.getName()))
{
Map<? extends ExecutableElement, ? extends AnnotationValue> annotationValues = elemUtils.getElementValuesWithDefaults(annotationMirror);
/****** Iterate over the annotation's values. ******/
for (ExecutableElement method : accessorValues.keySet())
{
if ("defaultBehavior".equals(method.getSimpleName().toString()))
{
Behavior defaultBehavior = (Behavior)( (VariableElement)annotationValues.get(method).getValue()).getConstantValue();
// This prints "NEW" or "NULL" correctly
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,annotationValues.get(method).toString());
// This prints null incorrectly (expect "NEW" or "NULL")
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, defaultBehavior + "");
}
}
}
}
}
}
return true;
}
}
答案 0 :(得分:3)
来自getConstantValue的文档:
“特别是,枚举常量不被认为是编译时常量。要获得常量值,字段的类型必须是基本类型或字符串。”
要获取枚举常量的值,请使用getAnnotation API或使用AnnotationValueVisitor。
答案 1 :(得分:1)
我遇到了类似的问题(除了我没有处理枚举,我需要非String /非原始常量的值)并通过{{3}访问源代码来解决它}。
这是一般食谱:
<强> 1。创建自定义TreePathScanner:
private static class CodeAnalyzerTreeScanner extends TreePathScanner<Object, Trees> {
private String fieldName;
private String fieldInitializer;
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public String getFieldInitializer() {
return this.fieldInitializer;
}
@Override
public Object visitVariable(VariableTree variableTree, Trees trees) {
if (variableTree.getName().toString().equals(this.fieldName)) {
this.fieldInitializer = variableTree.getInitializer().toString();
}
return super.visitVariable(variableTree, trees);
}
<强> 2。在AbstractProcessor中,通过覆盖init方法保存对当前编译树的引用:
@Override
public void init(ProcessingEnvironment pe) {
super.init(pe);
this.trees = Trees.instance(pe);
}
第3。获取VariableElement的初始化源代码(在您的情况下为枚举):
// assuming theClass is a javax.lang.model.element.Element reference
// assuming theField is a javax.lang.model.element.VariableElement reference
String fieldName = theField.getSimpleName().toString();
CodeAnalyzerTreeScanner codeScanner = new CodeAnalyzerTreeScanner();
TreePath tp = this.trees.getPath(theClass);
codeScanner.setFieldName(fieldName);
codeScanner.scan(tp, this.trees);
String fieldInitializer = codeScanner.getFieldInitializer();
就是这样!有了这个,您应该能够获得初始化值,对于带注释的字段,您通常不能使用VariableElement.getContantValue(即任何不是字符串或基元的“常量”)。
有关更多阅读和示例,请阅读此Compiler Tree API。