【问题标题】:Java Annotation Processor: only generate a source file if it does not existJava Annotation Processor:仅在源文件不存在时生成源文件
【发布时间】:2021-01-13 23:02:41
【问题描述】:

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

因为我只是在学习,所以我创建了一个注释处理器,正如 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 时,有什么方法可以防止生成的源文件夹被清除?还是有更好的方法来实现我想要实现的目标?

【问题讨论】:

    标签: java


    【解决方案1】:

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

    例如,这些文件以src/generatedgenerated_src 结尾。编辑此文件会使它们不会(完全)生成,而这反过来又意味着您的代码库现在是一个谎言:它在一个强烈暗示它们已生成的目录中有未生成的源文件。

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

    解决方案是在生成的文件夹中不包含这些文件;它们应该被检查到版本控制中,并且它们不应该被工具(IDE、构建系统等)视为可以轻易删除的谷壳。但是,注释处理器系统没有这样一个目录的概念。

    文件管理器确实让您可以获取源文件本身,因此您可以考虑将其写到那里,这似乎是最安全的选择。

    请注意,与您类似的其他系统称为“骨架”系统或“脚手架”系统:例如,maven's archetype system

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

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

    1. 您可以这样注释:package com.foo; @DbModel class PersonTemplate {String name; LocalDate dateOfBirth;}
    2. 然后该工具将生成一个源文件,其中包含package com.foo; public class Person { public String getName() { ... }} 以及更多样板文件和数据库查询方法等。
    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 不在源代码管理中,可以通过工具随意删除。

    换句话说,3个选项:

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

    【讨论】:

    • 关于选项1,如何使用文件管理器获取源目录?
    • 使用 Filer 的 .getResource(StandardLocation.SOURCE_PATH) 并找到一个您知道必须存在的源文件,然后对路径进行一些手术。这个位置没有 .write() 选项是有原因的;你不应该这样做;选项 2 和 3 更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    • 1970-01-01
    • 2021-09-21
    • 1970-01-01
    • 1970-01-01
    • 2013-10-19
    相关资源
    最近更新 更多