Java AnnotationProcessing - 获取Annotation的字段

时间:2017-08-30 16:31:26

标签: java annotations annotation-processing

根据API AnnotationProcessing我有一个问题。 这是一个小例子。

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.FIELD)
public @interface MyAnnotation
{
   String strNumberOne() default "";

   String strNumberTwo() default "";

   String strNumberThree() default "";
}


public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
    // I do not know how to beginn here
      return true;
   }
}

public class MyClass
{
   @MyAnnotation(strNumberOne="one", strNumberTwo= "two")
   private String strARandomString;
}

现在我想阅读注释中声明的字段,如果没有声明字段,我的程序应该采用默认值。

我想在列表中写入值。最后,我的名单应该是这样的:

LinkedList<String> s = new LinkedList<>();
s.add(strNumberOne); // "one"
s.add(strNumberTwo); // "two"
s.add(strNumberThree); // (default) ""

我该怎么做?我发现了一种可以提供帮助的方法。它位于Interface&#34; Elements&#34;方法名称是&#34; getElementValuesWithDefaults()&#34;。但我不知道如何使用它.. 另外,我想知道TypeElement和Element之间的区别。 我很感谢每一个答案! :)

祝你好运!

1 个答案:

答案 0 :(得分:1)

如果MyAnnotation是您的处理器支持的注释,那么您只需编写如下内容:

@Override
public boolean process(Set<? extends TypeElement> annotations,
                       RoundEnvironment           env) {
    if (shouldClaim(annotations)) {
        for (Element e : env.getElementsAnnotatedWith(MyAnnotation.class)) {
            MyAnnotation a = e.getAnnotation(MyAnnotation.class);

            String str1 = a.strNumberOne();
            String str2 = a.strNumberTwo();
            String str3 = a.strNumberThree();
            // Add them to a List or whatever you need.
        }

        return true;
    }
    return false;
}

private boolean shouldClaim(Set<? extends TypeElement> annotations) {
    Set<String> supported = getSupportedAnnotationTypes();
    for (TypeElement a : annotations) {
        if (supported.contains(a.getQualifiedName().toString()))
            return true;
    }
    return false;
}

shouldClaim方法的逻辑由process的文档解释。如果你的注释支持例如,那将会更复杂*name.*形式的类型,但通常不会。 (有关这些含义的说明,请参阅getSupportedAnnotationTypes。)

如果MyAnnotation 不是处理器支持的注释,那么需要通过getElementValuesWithDefaults ,如果< / em>它是您正在编译的包中声明的类型。由于在编译期间发生了注释处理,因此对于正在编译的源文件,类文件尚不存在,这就是我们使用Element API的原因。

Element表示某种声明,例如类,方法或变量。 TypeElement表示类,接口,枚举或注释类型声明。关于我们可以用它做什么,TypeElement类似于Class,除了我们可以将TypeElement用于不必编译的类。

要通过元素API获取注释值,您可以执行以下操作:

Elements    elements     = processingEnv.getElementUtils();
TypeElement myAnnotation = elements.getTypeElement("com.example.MyAnnotation");

for (Element e : env.getElementsAnnotatedWith(myAnnotation)) {
    for (AnnotationMirror mirror : e.getAnnotationMirrors()) {
        DeclaredType annotationType = mirror.getAnnotationType();
        Element      annotationDecl = annotationType.asElement();

        if (myAnnotation.equals(annotationDecl)) {
            Map<? extends ExecutableElement, ? extends AnnotationValue> values =
                elements.getAnnotationValuesWithDefaults(mirror);

            String str1 = (String) getValue(values, "strNumberOne");
            String str2 = (String) getValue(values, "strNumberTwo");
            String str3 = (String) getValue(values, "strNumberThree");
            // ...
        }
    }
}

private Object getValue(Map<? extends ExecutableElement,
                            ? extends AnnotationValue> values,
                        String name) {
    for (Map.Entry<? extends ExecutableElement,
                   ? extends AnnotationValue> e : values.entrySet()) {
        if (name.contentEquals(e.getKey().getSimpleName()))
            return e.getValue().getValue();
    }
    return null;
}

这很痛苦,但我们只需要使用元素API 如果我们感兴趣的注释是正在编译的类之一。

我们可能还希望找到AnnotationMirror和/或AnnotationValue使用Messager.printMessage重载之一在特定元素上产生某种消息,这些重载采用上述之一对象作为参数。