Java Annotation Processor:仅当源文件不存在时才生成源文件



我正在尝试编写一个生成源文件的注释处理器,但不会覆盖在以前运行注释处理器时生成的源文件。

因为我只是在学习,我创建了一个注释处理器,正如Ryan Harter在以下视频中所描述的那样:https://www.youtube.com/watch?v=IPlDL4EsY08.

我希望能够生成一次源文件,然后允许开发人员手动编辑,而不用担心手动更改会被后续运行的注释处理器覆盖。这可能不是常态,但我可以想到几个用例,在这些用例中,它会被证明是有益的。

我希望修改的AbstractProcessor子类中的特定代码是:

try {
JavaFile file = JavaFile
.builder(builderType.packageName(), builder)
.build();
file.writeTo(filer);
} catch (IOException e) {
messager.printMessage(Diagnostic.Kind.ERROR, "Failed to write file for element", el);
}

现在,在我看来,每次为我的gradle项目运行构建任务时,生成的源文件夹中的所有文件都会被删除。这意味着,即使生成的源文件在运行构建任务之前就已经存在,我在注释处理器中为检查给定生成源文件的存在而编写的任何代码都将始终返回否定的结果。每次使用注释处理器重新运行javac时,是否有任何方法可以防止生成的源文件夹被擦除?或者有更好的方法来实现我想要实现的目标吗?

注释处理器的输出被认为是编译的产物。就像类文件一样,默认情况下,所有相关的系统、标准和样式指南都会将这些文件[A]排除在版本控制之外,而[B]则以一种激进的方式被认为是不相关的、可删除的垃圾。任何clean命令都会删除这些,它们会被放弃覆盖,工具可能会因为难以辨别的原因而决定删除它们:它们都被认为具有不包含任何重要内容的特性,它们只是一个过程的产物;这个过程很容易重复。

例如,这些文件最终位于src/generatedgenerated_src中。编辑这个文件会使它们不(完全(生成,这反过来意味着你的代码库现在是一个谎言:它在一个目录中有未生成的源文件,这强烈表明它们是生成的。

疼痛随之而来;无法解决的痛苦。

解决方案是在生成的文件夹中不包含这些文件;它们应该被检查到版本控制中,不应该被工具(IDE、构建系统等(认为是微不足道的可删除的碎片。然而,注释处理器系统不具有这种目录的内置概念。

文件管理器确实可以让你访问源文件本身,所以你可以考虑把它写在那里,这似乎是最安全的选择

请注意,其他与您类似的系统被称为"骨架"系统或"脚手架"系统:例如,maven的原型系统。

我认识的很多人都没有使用注释处理器来完成这项工作。您可能只是使用了错误的工具链。

另一种解决方案是将自定义代码导入到一个文件中,然后该文件被认为是完全生成的。例如,有以下规则:

  1. 您注释的内容如下:package com.foo; @DbModel class PersonTemplate {String name; LocalDate dateOfBirth;}
  2. 然后,该工具将生成一个包含package com.foo; public class Person { public String getName() { ... }}以及更多样板和DB查询方法等的源文件
  3. 此文件将在顶部生成一个注释:// Generated code. Don't edit this code; add methods to PersonExtras instead
  4. 在AP的编译运行过程中,您扫描一个名为com.foo.PersonExtras的类。如果它存在,你可以扫描它里面的静态方法。对于每个这样的方法,你都要检查第一个arg是否是Person。例如,public void foo(Person p) {}。如果是,则在Person中生成一个链接到它的实例方法:public void foo() { PersonExtras.foo(p); }。如果不是,则在Person中生成一个链接到它的静态方法

您的Person代码现在是编译的产物,您的AP可以在没有用户输入的情况下随意完全重新创建,但它可以扩展。PersonExtras类可以放在源代码管理中,只在您通常的src目录中,而Person.java不在源代码控制中,可以通过工具随意删除。

换句话说,3个选项:

  1. 使用filer查找源目录并在那里生成文件。这可能不会成功,而且有点奇怪
  2. 不要将此产品作为注释处理器编写,而是将其作为独立工具或插件编写到现有的脚手架生成器系统中,如maven的原型
  3. 解决生成的类以其他方式可扩展的问题,例如,使用另一个类的字段和方法作为如何生成代码的指南:从而确保AP生成的源文件可以保持"永远不会被人工编辑">

最新更新