Java AnnotationProcessing - 获取注释的字段

Java AnnotationProcessing - Get fields of the Annotation

我根据 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) ""

我该怎么做?我找到了一种可以提供帮助的方法。它在接口 "Elements" 中,方法名称是 "getElementValuesWithDefaults()"。但是不知道怎么用。。 我也想知道 TypeElement 和 Element 之间有什么区别。 我感谢每一个答案! :)

此致!

如果 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. It would be more complicated if your annotation supports e.g. * or a type of the form name.*, but in general you don't. (See getSupportedAnnotationTypes 的文档中进行了解释,以说明其含义。)

如果MyAnnotation不是你的处理器支持的注释,那么你需要通过getElementValuesWithDefaults if 它是您正在编译的包中声明的类型。因为注释处理发生在编译期间,class文件对于正在编译的源文件还不存在,这就是为什么我们使用Element API 相反。

Element 表示某种声明,例如 class、方法或变量。 TypeElement 表示 class、接口、枚举或注解类型声明。 TypeElement 类似于 Class 我们可以用它做什么,除了我们可以使用 TypeElement 来代替 class ,而 class 不一定要编译。

要通过元素 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 if 我们感兴趣的注解是 classes 之一正在编译中。

我们可能还想找到 AnnotationMirror and/or AnnotationValue 使用 Messager.printMessage 重载之一在特定元素上引起某种消息上述对象之一作为参数。