-- 选项1-从命令行手动编译 ---
我尝试做你想要的事情,即访问来自处理器的所有类,正如评论中所说,javac总是编译所有类,并且从RoundEnvironment中,我可以访问正在编译的所有类,每次(即使没有文件更改),只要所有类都显示在要编译的类列表中。
我已经对两个接口进行了几次测试,其中一个(A)依赖于另一个(B)(extends),我有以下场景:
- 如果我要求编译器明确编译仅具有依赖关系(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: ...]
...
重要的细节在于编译器在第一种情况下将依赖项作为隐式对象加载进行编译。在第二种情况下,它将作为待编译对象的一部分加载(您可以看到在解析提供的类之后开始搜索其他路径的文件)。而且似乎隐式对象不包含在注释处理列表中。
有关编译过程的更多详细信息,请查看
Compilation Overview。它没有明确说明选择哪些文件进行处理。
在这种情况下的解决方案是始终将所有类添加到编译器命令中。
--- 选项2 - 从Eclipse编译 ---
如果您从Eclipse编译,则增量构建会使处理器失败(未经测试)。但我认为您可以通过请求进行干净构建(项目>清理...,也未经测试)或编写一个Ant构建来绕过它,该构建始终清除类目录并设置
Eclipse的Ant Builder。
--- 选项3 - 使用构建工具 ---
如果您使用其他构建工具,如Ant、Maven或Gradle,则最好的解决方案是将源代码生成与编译分开。您还需要在先前的步骤中(或者在Maven / Gradle中使用多项目构建时的单独子项目中)编译处理器。这将是最佳方案,因为:
- 对于处理步骤,您始终可以进行完整的清理“编译”,而不实际编译代码(使用javac选项
-proc:only
仅处理文件)
- 有了生成的源代码,如果您使用Gradle,它将足够聪明,如果未更改生成的源文件,则不重新编译它们。Ant和Maven只会重新编译所需的文件(生成的文件及其依赖项)。
对于第三个选项,您还可以设置一个Ant构建脚本,将其作为在Java构建器之前运行的Eclipse构建器从Eclipse生成那些文件。在某些特殊文件夹中生成源文件,并将其添加到Eclipse的类路径/构建路径中。