-- 选项 1 - 从命令行手动编译 ---
我试图做你想做的事,即从处理器访问所有类,正如人们评论的那样,javac 总是编译所有类,并且从 RoundEnvironment 我确实可以访问所有正在编译的类,每次(即使没有文件更改),有一个小细节:只要所有类都显示在要编译的类列表中。
我用两个接口做了一些测试,其中一个(A)依赖于(B)另一个(扩展),我有以下场景:
- 如果我要求编译器只显式编译具有依赖项(A)的接口,将 java 文件的完整路径传递到命令行,并将输出文件夹添加到类路径,只有我传递到命令行的接口得到处理。
- 如果我只显式编译(A)并且不将输出文件夹添加到类路径中,编译器仍然只处理接口(A)。但它也给了我警告:
Implicitly compiled files were not subject to annotation processing.
- 如果我使用 * 或将两个类都传递给编译器到命令行,那么我得到预期的结果,两个接口都得到处理。
如果您将编译器设置为详细,您将收到一条明确的消息,显示每轮将处理哪些类。这是我显式传递接口(A)时得到的:
Round 1:
input files: {com.bearprogrammer.test.TestInterface}
annotations: [com.bearprogrammer.annotation.Service]
last round: false
这就是我添加两个类时所得到的:
Round 1:
input files: {com.bearprogrammer.test.AnotherInterface, com.bearprogrammer.test.TestInterface}
annotations: [com.bearprogrammer.annotation.Service]
last round: false
在这两种情况下,我都看到编译器解析了这两个类,但顺序不同。对于第一种情况(仅添加了一个接口):
[parsing started RegularFileObject[src\main\java\com\bearprogrammer\test\TestInterface.java]]
[parsing completed 15ms]
[search path for source files: src\main\java]
[search path for class files: ...]
[loading ZipFileIndexFileObject[lib\processor.jar(com/bearprogrammer/annotation/Service.class)]]
[loading RegularFileObject[src\main\java\com\bearprogrammer\test\AnotherInterface.java]]
[parsing started RegularFileObject[src\main\java\com\bearprogrammer\test\AnotherInterface.java]]
对于第二种情况(添加了所有接口):
[parsing started RegularFileObject[src\main\java\com\bearprogrammer\test\AnotherInterface.java]]
...
[parsing started RegularFileObject[src\main\java\com\bearprogrammer\test\TestInterface.java]]
[search path for source files: src\main\java]
[search path for class files: ...]
...
这里重要的细节是编译器在第一种情况下将依赖项作为编译的隐式对象加载。在第二种情况下,它将作为待编译对象的一部分加载(您可以看到这一点,因为它在解析提供的类后开始搜索文件的其他路径)。并且似乎隐式对象不包含在注释处理列表中。
有关编译过程的更多详细信息,请查看此编译概述。这并没有明确说明要提取哪些文件进行处理。
这种情况下的解决方案是始终将所有类添加到编译器的命令中。
--- 选项 2 - 从 Eclipse 编译 ---
如果您从 Eclipse 编译,增量构建将使您的处理器失败(尚未测试)。但我认为你可以绕过要求一个干净的构建(Project > Clean ...,也没有测试过)或编写一个始终清理类目录并从 Eclipse 设置一个 Ant Builder的 Ant 构建。
--- 选项 3 - 使用构建工具 ---
如果您使用的是其他构建工具,例如 Ant、Maven 或 Gradle,最好的解决方案是在编译之外的单独步骤中生成源代码。您还需要在单独的上一步中编译您的处理器(如果在 Maven/Gradle 中使用多项目构建,则需要一个单独的子项目)。这将是最好的情况,因为:
- 对于处理步骤,您始终可以在不实际编译代码的情况下进行完全干净的“编译”(使用
-proc:only
javac 中的选项仅处理文件)
- 生成的源代码到位后,如果您使用 Gradle,那么如果生成的源文件没有更改,则无需重新编译它们就足够聪明了。Ant 和 Maven 只会重新编译所需的文件(生成的文件及其依赖项)。
对于这第三个选项,您还可以设置一个 Ant 构建脚本,以从 Eclipse 作为构建器生成这些文件,该构建器在您的 Java 构建器之前运行。在某个特殊文件夹中生成源文件并将其添加到 Eclipse 中的类路径/构建路径中。