如何在 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
的文件中读取已注册的类型
- 获取用您的注释注释的元素。
- 如果是最后一轮,您只需使用唯一记录集更新文件并生成代码。
你每一轮都读取文件,但在最后一轮只写入一次。
我正在编写一个注解处理器,它需要在当前模块中收集所有带有特定注解的 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.javaclass 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 的文件中读取已注册的类型
- 获取用您的注释注释的元素。
- 如果是最后一轮,您只需使用唯一记录集更新文件并生成代码。
你每一轮都读取文件,但在最后一轮只写入一次。