gpt4 book ai didi

java - AnnotationProcessor 使用多个源文件创建一个文件

转载 作者:搜寻专家 更新时间:2023-10-30 19:44:50 28 4
gpt4 key购买 nike

我有两个带有方法的类,我想将两个类的方法合并到一个类中。

@Service("ITestService")
public interface ITest1
{
@Export
void method1();
}

@Service("ITestService")
public interface ITest2
{
@Export
void method2();
}

结果应该是:

public interface ITestService extends Remote
{
void method1();
void method2();
}

我的 AnnotationProcessor 的第一次运行生成了正确的输出(因为 RoundEnvironment 包含这两个类)。

但是如果我编辑其中一个类(例如添加一个新方法),RoundEnviroment 仅包含编辑后的类,因此结果如下(将 newMethod() 添加到接口(interface) ITest1)

public interface ITestService extends Remote
{
void method1();
void newMethod();
}

现在缺少 method2。我不知道如何解决我的问题。有没有办法(环境)访问项目中的所有类?或者有其他方法可以解决这个问题吗?

生成类的代码很长,所以这里简要描述一下我是如何生成类的。我使用 env.getElementsAnnotatedWith(Service.class) 遍历元素并提取方法并将它们写入新文件:

FileObject file = null;
file = filer.createSourceFile("com/test/" + serviceName);
file.openWriter().append(serviceContent).close();

最佳答案

-- 选项 1 - 从命令行手动编译 ---

我尝试做你想做的,即从处理器访问所有类,正如人们评论的那样,javac 总是编译所有类,并且从 RoundEnvironment 中我确实可以访问所有正在编译的类,每次(甚至当没有文件更改时),有一个小细节:只要所有类都显示在要编译的类列表中。

我用两个接口(interface)做了一些测试,其中一个 (A) 依赖于 (B) 另一个(扩展),我有以下场景:

  1. 如果我要求编译器仅显式编译具有依赖项 (A) 的接口(interface),将 java 文件的完整路径传递到命令行,并将输出文件夹添加到类路径,则只有我传递到的接口(interface)命令行得到处理。
  2. 如果我只显式编译 (A) 并且不将输出文件夹添加到类路径,编译器仍然只处理接口(interface) (A)。但它也给了我警告:Implicitly compiled files were not subject to annotation processing.
  3. 如果我使用 * 或将两个类都传递给编译器到命令行,那么我会得到预期的结果,两个接口(interface)都会得到处理。

如果您将编译器设置为冗长,您将收到一条明确的消息,显示每轮将处理哪些类。这是我显式传递接口(interface) (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

在这两种情况下,我都看到编译器解析了这两个类,但顺序不同。对于第一种情况(只添加了一个接口(interface)):

[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]]

对于第二种情况(添加所有接口(interface)):

[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 Builder from Eclipse 的 Ant 构建。 .

--- 选项 3 - 使用构建工具 ---

如果您使用的是 Ant、Maven 或 Gradle 等其他构建工具,最好的解决方案是将源代码生成与编译分开进行。您还需要在单独的前一步中编译您的处理器(如果在 Maven/Gradle 中使用多项目构建,则需要单独的子项目)。这将是最佳方案,因为:

  1. 对于处理步骤,您始终可以在不实际编译代码的情况下进行完全干净的“编译”(使用 javac 中的选项 -proc:only 来仅处理文件)
  2. 有了生成的源代码,如果您使用的是 Gradle,那么如果生成的源文件没有更改就不会重新编译它们就足够聪明了。 Ant 和 Maven 只会重新编译所需的文件(生成的文件及其依赖项)。

对于第三个选项,您还可以设置一个 Ant 构建脚本来从 Eclipse 中生成这些文件,作为一个在 Java 构建器之前运行的构建器。在一些特殊文件夹中生成源文件,并将其添加到 Eclipse 中的类路径/构建路径。

关于java - AnnotationProcessor 使用多个源文件创建一个文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13397987/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com