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

Dan*_*dei 5 java intellij-idea annotation-processing

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

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

src/main/java/org/example/A.java
@Annotation
class A {}
Run Code Online (Sandbox Code Playgroud) src/main/java/org/example/B.java
@Annotation
class B {}
Run Code Online (Sandbox Code Playgroud)

我想生成一个类:

目标/生成源/org/example/Module.java
class Module {
  String getModuleClasses() {
    return Arrays.asList(
      "org.example.A",
      "org.example.B"
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

这在 Maven 中有效,但是当我修改 class 时A,IntelliJ 为我的注释处理器提供了 aRoundEnvironment作为A单个根元素。

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

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

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

Ahm*_*neh 2

解决此问题的一种方法是在构建之间使用某种注册表,例如,您可以将服务中注释的类型(例如元信息中的样式)存储起来

因此,在您的处理器中,您将代码生成推迟到最后一轮处理,并且在生成代码后,您将文件中的类型存储到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);
Run Code Online (Sandbox Code Playgroud)

当然,您需要检查是否有重复的条目。

在生成代码之前的某个时刻,读取类型并基于该类型生成代码

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

Run Code Online (Sandbox Code Playgroud)

文件内容可能看起来像这样

org.foo.bar.A
org.foo.bar.B
Run Code Online (Sandbox Code Playgroud)

这样做的问题是,当您将代码生成推迟到最后一轮时,您生成的代码将不会被任何其他处理器(例如 dagger2)选取,并且有时文件可能会以不再存在的类的记录结束。

总之,您在处理器内执行以下操作

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

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