java - 注释处理器是否可以访问上一轮生成的类型?

标签 java annotations annotation-processing

我有一个注释处理器,它为每个注释类生成一个 ID 类。我希望类能够引用同一编译单元中其他类生成的 ID 类型。不幸的是,注释处理器似乎总是将生成的类的类型给出为 ERROR,即使该类型是在前一轮编译中生成的或由完全独立的处理器生成的。有解决办法吗?

这是一个最小的例子。假设我有以下类(class):

package tmp;

@MyAnnotation
public class Foo {
  private Foo me;
  private FooId myId;
}

它首先由这个注释处理器处理以生成 ID:

@SupportedAnnotationTypes("tmp.proc.MyAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class CreateIdProcessor extends AbstractProcessor {
  @Override
  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    for (Element elem : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {
      System.out.println("Writing ID for " + elem.getSimpleName());
      try {
        Writer file = processingEnv.getFiler().createSourceFile(elem + "Id").openWriter();
        file.write(String.format("package tmp; public class %sId {}", elem.getSimpleName()));
        file.close();
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }
    return false;
  }
}

然后由这个注释处理器处理以分析类型:

@SupportedAnnotationTypes("tmp.proc.MyAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class CheckIdProcessor extends AbstractProcessor {
  @Override
  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    for (Element elem : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {
      for (Element element : elem.getEnclosedElements()) {
        System.out.printf("%s = %s (%s)\n", element.getSimpleName(), element.asType(), element.asType().getKind());
      }
    }
    return false;
  }
}

运行构建的输出如下所示:

Writing ID for Foo
<init> = ()void (EXECUTABLE)
me = tmp.Foo (DECLARED)
myId = FooId (ERROR)

一切都编译正常,但第二个处理器将 myId 的类型视为错误,即使它是由第一个处理器生成的(并且 FooId 类确实存在于输出 jar 中)。这可以防止注释处理器分析 FooId 以找出它所属的包以便导入它。这个问题有什么解决方法吗?

最佳答案

Java Annotation Process 轮流执行其工作。在每一轮中,它将运行所有适用的注释处理器,然后编译输出。 Annotation Processor API 还跟踪哪些类已被处理,并且只处理一次。您遇到的问题是您的 CreateIdProcessorCheckIdProcessor 正在寻找它们的同一轮中生成类。因为 FooIdCheckIdProcessor 运行之前没有被编译,调用 getEnclosedElements() 返回的元素是 ERROR 元素。

简而言之,您的第二个处理器将 FooId 字段类型视为错误,因为生成了 FooId 的源代码,但尚未编译。

这是您可以运行的实验。这个注释处理器将打印出在给定回合中处理的所有新类。 FooId 出现在 Round: 1 下,而 Foo 会出现在 Round: 0 下:

Round: 0
Foo = tmp.Foo (DECLARED)
<init> = ()void (EXECUTABLE)
me = tmp.Foo (DECLARED)
myId = FooId (ERROR)
Writing ID for Foo
Round: 1
FooId = tmp.FooId (DECLARED)
Round: 2
Round: 3

这是我为此使用的注释处理器:

@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class OutputRoundProcessor extends AbstractProcessor {
  private int round = 0;
  @Override
  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    System.out.println("Round: " + round);
    for (Element element : roundEnv.getRootElements()) {
      System.out.printf("%s = %s (%s)\n", element.getSimpleName(), element.asType(), element.asType().getKind());
    }
    round++;
    return false;
  }
}

关于java - 注释处理器是否可以访问上一轮生成的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30113866/

相关文章:

java - 正则表达式 "reluctant"量词行为不当

java - 在 swing 中关闭父窗口

java - 如何处理Spring Boot注释中的403禁止错误?

java - JAXB 和 JPA 注释。是否有任何强有力的论据支持更喜欢字段访问而不是属性访问?

java - 在Java注释处理器中获取数组类型

Android项目+Eclipse+注解处理

java - 许多 drawBitmap 后图像质量变差

java - 当在方法级别内部使用 @PreAuthorize 或 @PostAuthorize 时,Class.getAnnotations() 不会返回类级别注释的完整列表

java - 使用注释处理器替换代码

java - eclipse java导入组织