Java注解处理器:仅在源文件不存在时生成一个源文件

3
我正在尝试编写一个注解处理器来生成源文件,但不会覆盖在先前运行注解处理器期间生成的源文件。
因为我还在学习中,所以我按照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时清除生成的源文件夹?或者是否有更好的方法来实现我想要完成的操作?
1个回答

1
注解处理器的输出被认为是编译的产品。与类文件一样,这些文件默认情况下都不会被版本控制系统、标准和样式指南保留,并且被视为不相关、可删除的废弃物。任何“clean”命令都将删除它们,它们会被随意覆盖,而工具可能会因难以辨别的原因而决定删除它们:它们都被假定为具有不包含任何重要内容的属性,它们只是一个过程的产物;这个过程可以轻松地重复。
例如,这些文件最终会出现在“src/generated”或“generated_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的类。如果它存在,则扫描其中的静态方法。对于每个这样的方法,检查第一个参数是否为Person。例如:public void foo(Person p) {}。如果是,则在Person中生成一个实例方法链接到它:public void foo() { PersonExtras.foo(p); }。如果不是,则在Person中生成一个静态方法链接到它。
你的个人代码现在是编译的产物,可以由你的AP随意地完全重新创建,而不需要用户输入,但它可以被扩展。 PersonExtras 类可以放置在源代码控制中,并且只需位于通常的 src 目录中,而 Person.java 不会位于源代码控制中,并且可以随意地被工具删除。
换句话说,有三个选项:
  1. 使用文件处理器查找源目录并在那里生成您的文件。这可能不成功,有点奇怪。
  2. 将此产品编写为独立工具或插件,集成到现有的脚手架生成系统中,如maven的原型。
  3. 通过其他方式解决所产生的类可扩展的问题,例如使用另一个类的字段和方法作为生成代码的指南:从而确保您的AP生成的源文件仍然“旨在永远不被人手编辑”。

关于选项1,如何使用过滤器来获取源目录? - undefined
1
使用Filer的.getResource(StandardLocation.SOURCE_PATH)方法,找到一个你知道必定存在的源文件,然后对路径进行一些操作。这个位置没有.write()选项是有原因的;你不应该这样做;选项2和3更好。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接