如何在 IntelliJ 增量构建中获取所有带有注释的元素?

How to get all elements with an annotation in an IntelliJ incremental build?

我正在编写一个注解处理器,它需要在当前模块中收集所有带有特定注解的 classes 并编写一个 class 来引用它们中的每一个。

为了简化一点,给定这些源文件:

src/main/java/org/example/A.java
@Annotation
class A {}
src/main/java/org/example/B.java
@Annotation
class B {}

我想生成一个class:

target/generated-sources/org/example/Module.java
class Module {
  String getModuleClasses() {
    return Arrays.asList(
      "org.example.A",
      "org.example.B"
    );
  }
}

这适用于 Maven,但是当我修改 class A 时,IntelliJ 为我的注释处理器提供了一个 RoundEnvironment,其中 A 作为单个根元素。

我了解 Gradle 支持增量编译 aggregating annotation processors 通过将所有源与注释匹配的假 RoundEnvironment 传递给注释处理器,但 IntelliJ 似乎没有任何类似的东西。 (也许 Gradle 个项目除外?)

当 IntelliJ 仅编译 class A 时,找到两个 class 的最佳方法是什么?

也许注释器可以保留一个带注释的列表 classes:在第一轮中从资源文件中读取列表,在每一轮中从列表中删除根元素并添加到列表中的元素是注释,并在最后一轮将列表写回资源文件?

解决此问题的一种方法是在构建之间使用某种注册表,例如,您可以存储服务中注释的类型,例如 meta-inf

中的样式

因此,在您的处理器中,您将代码生成推迟到最后一轮处理,并且在生成代码后,您将文件中的类型存储到 META-INF

下的文件中
FileObject resource = processingEnv.getFiler()
                    .createResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/annotatedtypes/"+fileName);
PrintWriter out = new PrintWriter(new OutputStreamWriter(resource.openOutputStream()));
            classes.forEach(out::println);

您当然需要检查重复条目。

在生成代码之前的某个时刻,阅读类型并根据它生成代码

FileObject resource = processingEnv.getFiler()
                        .getResource(StandardLocation.CLASS_OUTPUT, "", "META-INF/annotatedtypes/"+fileName);
new BufferedReader(new InputStreamReader(resource.openInputStream())).lines().forEach(classes::add);

文件内容可能如下所示

org.foo.bar.A
org.foo.bar.B

问题在于,当您将代码生成推迟到最后一轮时,您生成的代码将不会被任何其他处理器(例如 dagger2)选取,而且有时文件可能以 [=40= 的记录结尾] 已经不存在了。

总而言之,在您的处理器中,您执行以下操作

  • 从位于 META-INF
  • 的文件中读取已注册的类型
  • 获取用您的注释注释的元素。
  • 如果是最后一轮,您只需使用唯一记录集更新文件并生成代码。

你每一轮都读取文件,但在最后一轮只写入一次。