获取注释处理器中生成的注释的所有值

Get all values of a generated Annotation in an Annotation Processor

我有一个 VariableElement 字段,它使用生成的注释进行注释(这就是我不能使用 field.getAnnotation(annotationClass) 的原因)。我需要获取传递给此注释的所有参数。

请注意,"a generated Annotation" 我的意思是注释 class 本身(不是注释的注释)本身是由注释处理器生成的。正在注解的field/class在手写源码里

看起来并没有那么难,到目前为止我想出了这个:

for (AnnotationMirror annotation : field.getAnnotationMirrors()) {
    Map<? extends ExecutableElement, ? extends AnnotationValue> annotationValueMap = annotation.getElementValues();

    messager.printMessage(Diagnostic.Kind.WARNING, annotation.toString() + ":" + annotationValueMap.toString());
}

我以为这样就可以了,但该字段的输出如下:

@MyAnnotation:{}

因此,处理器确实识别出该字段已注释,但我无法访问传递的参数。即使该字段已明确注释并且确实通过注释传递参数(它必须这样做,因为注释定义了必需的参数并且没有默认值):

@MyAnnotation(max = 387, min = 66876, ...)
private Integer myField;

这里是生成的注释代码:

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.FIELD)
public @interface MyAnnotation {
  int max();

  boolean allowAuto();

  int min();
}

我已经多次干净地编译项目,处理器从未看到这些值。我在这里忽略了什么?处理器显然可以看到注释本身,但传递给它的参数是隐藏的。

使用 VariableElement

提供的 getAnnotation(MyAnnotation.class)

在您的示例代码中,您可以执行此操作以获取 minmax 参数

MyAnnotation myAnnotation= field.getAnnotation(MyAnnotation.class);
int max = myAnnotation.max();
int min = myAnnotation.min();

除非注解成员 returns class/class[] 值,否则这将起作用,如果您尝试使用此方法获取值,您将在其中获得异常。

有关如何获取 class 文字值的更多信息,请参见此答案

或者使用注解镜像

for (AnnotationMirror annotation : field.getAnnotationMirrors()) {
    Map<? extends ExecutableElement, ? extends AnnotationValue> annotationValueMap = annotation.getElementValues();
    annotationValueMap.forEach((element, annotationValue) -> {
        messager.printMessage(Diagnostic.Kind.WARNING, element.getSimpleName().toString() + ":" + annotationValue.getValue());
    });
}

如果字段上有多个注释,则可以遍历注释镜像并使用检查 types.isSameType(annotationMirror.getAnnotationType(), elements.getTypeElement(MyAnnotation.class.getName()).asType()) 找到您感兴趣的注释

回想一下,注释处理器 运行 作为编译器的一部分,在称为 "rounds" 的步骤中。这个过程 运行s 迭代直到没有新的代码要编译,然后处理器得到最后一次机会 运行 (对于这个答案不是必需的,但对更多上下文有帮助)。每轮只有新创建的类型直接交给处理器检查。

这里似乎发生的是, 一轮中,您发出了一个新的注释类型,这应该允许处理器观察提交编译的某些代码的某些特征.但是,在给定回合中创建的任何类型在下一轮开始之前都不会被编译。

对于这个问题,我们 运行 在这里陷入了冲突 - 编译了一些 Java 源代码,这些源代码使用了 尚不存在的注释 。处理器首先创建注释,然后尝试从那些部分编译的源代码中读取新创建的注释。不幸的是,在注释被编译之前,我们无法真正读取注释。相反,我们需要等到下一轮(一旦注释本身已编译),然后返回已完成编译的 class 并检查它。

这可以自己实现,不会太麻烦,但最简单的方法通常是依赖 google/auto 项目(特别是自动公共库,参见 https://github.com/google/auto/tree/master/common),并扩展它们BasicAnnotationProcessor class。它支持的一个很好的特性是自动检查类型并检查是否存在任何编译问题——如果存在,它们将被推迟到下一轮,这样您就可以在没有任何类型解析问题的情况下处理它们。