当处理器依赖于注释值中的 class 时,选择 Gradle 增量注释处理器类别

Choosing Gradle incremental annotation processor category when processor depends on a class in annotation value

我有一个简单的 annotation processor 应用如下:

@DiffElement(diffReceiver = Renderer.class)
class ViewState {
  String getHello();
  int getWorld();
}

class Renderer {
  void renderHello(String hello);
  void renderWorld(int world);
}

为了让这个处理器工作,get-函数和Renderer-接口函数参数的名称必须匹配。它会检查这一点,并使用注释的参数来查看提供的 class 并基于此生成一些代码。

它生成一个文件。

我已经阅读了 Incremental annotation processing 上的文档,但我无法决定将哪个类别应用于此处理器。以下是我的考虑:

问题:

it can't be aggregating, because it doesn't have any annotation on Renderer class, so according to the above documentation, processor won't be called whenever Renderer class changes, because processor hasn't registered to process this file, so this will lead to errors in generated result.

这不会是一个直接的答案,但我认为它仍然可以回答你的问题:据我所知,这句话是你问题的真正根源。任何温和的增量系统都会让你在这里失败,而不仅仅是 Gradle 的 "aggregating" 模式(例如,尝试在一个简单的 Eclipse 项目中使用你的处理器,甚至可能是 IntelliJ,尽管我已经那里的结果好坏参半。

如果您真的想强制对未注释类型的更改将导致您的注释处理器再次 运行,则您不能将注释处理器限制为该注释,但必须 return来自 getSupportedAnnotationTypes() 的神奇 "*" 值,表明任何更改 class 必须触发处理器重新 运行。 From the Javadoc for this method:

Finally, "*" by itself represents the set of all annotation types, including the empty set. Note that a processor should not claim "*" unless it is actually processing all files; claiming unnecessary annotations may cause a performance slowdown in some environments.

理想情况下,您只需制作第二个(或第三个等)注释来提供此提示,但这并不总是可行的,这就是允许您使用此通配符选项的原因

Do I understand documentation correctly? Or can some category still be applied to this processor

关于处理器类别的文档非常简短,而且在我看来,缺少示例。我花了很多时间来研究这些文档,构建一些简单的实验项目。因此,据我所知,如果我最后确实正确地计算出它们,则可以应用一个类别:)

你这么说

it can't be isolating, because it doesn't derive everything from annotated element's AST, as it also inspects a class from annotation argument

这不完全正确,我会解释原因。 如 documentation 中所述,隔离处理器

must make all decisions (code generation, validation messages) for an annotated type based on information reachable from its AST. This means you can analyze the types' super-class, method return types, annotations etc., even transitively.

“Even transitively”短语在这里非常重要 - 这意味着,您不仅可以分析带注释的类型的 AST,还可以分析其中一些方法的 return 类型的 AST,然后,比方说,那种类型的 superclass...

据我了解,您可以通过 AST 从带注释的元素中发现的每种类型都是带注释的类型(或一般元素)的依赖项。如果更改了依赖项,则依赖类型需要重新编译。所以当Rendererclass改变时,ViewState会被重新编译从而重新处理,因为它引用了Renderer 作为其注解参数。超类型、超接口、方法的 return 类型、方法参数的类型、注释 class 参数,... - 所有这些都被视为依赖类型。

因此,您的注释处理器实际上可以隔离


P.S. 如果隔离不起作用,无论出于何种原因,请确保注释保留为 CLASS 或更高。

P.P.S. 我发现注释处理中的增量是一个非常阴暗的话题,充满了惊喜和水下岩石。我自己发现的经验法则是,几乎每一个经过一些调整的处理器都可以被隔离,除非它真的需要根据许多输入生成一个实体。而且,重要的是,前提是这些输入在参考文献方面彼此完全无关,甚至位于不同的库中。