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

时间:2019-03-14 21:21:48

标签: java annotations annotation-processing

我有一个VariableElement字段,该字段带有生成的注释(这就是为什么我不能使用field.getAnnotation(annotationClass)的原因)。我需要将所有参数传递给该批注。

请注意,“生成的注释”是指注释类本身(不是带注释的类)实际上是由注释处理器生成的。注释的字段/类在手写的源代码中。

看起来好像没有那么难,到目前为止,我已经提出了:

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();
}

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

2 个答案:

答案 0 :(得分:2)

回想一下,注释处理器在称为“回合”的步骤中作为编译器的一部分运行。此过程将反复运行,直到没有新代码可编译为止,然后处理器获得了最后运行的机会(此答案不是必需的,但对于更多的上下文很有帮助)。每轮只将直接新创建的类型提供给处理器进行检查。

这里似乎发生的事情是,在 回合中,您正在发出新的注释类型,这应允许处理器观察有关提交的要编译的某些代码的某些功能。但是,在下一轮开始之前,尚未编译在给定轮次中创建的任何类型。

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

这可以自己实现,没有太多麻烦,但是最简单的方法通常是依靠google / auto项目(特别是自动公共库,请参见https://github.com/google/auto/tree/master/common),并扩展其{{1} }类。它支持的一项不错的功能是自动检查类型并检查是否存在任何编译问题-如果是,则将它们推迟到以后再进行,这样您就可以处理它们而没有任何类型解析问题。

答案 1 :(得分:1)

使用VariableElement提供的getAnnotation(MyAnnotation.class)

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

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

这将起作用,除非注释成员返回class/class[]值,如果您尝试使用此方法获取值,则将获得异常。

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

How to read a Class[] values from a nested annotation in an annotation processor

或使用注释镜

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())来查找您感兴趣的注释