当前位置: 首页 > 知识库问答 >
问题:

注释处理,RoundEnvironment.processIngover()

令狐凌
2023-03-14

在阅读Java中的自定义注释处理器的代码时,我注意到处理器的process方法中的这段代码:

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
  if (!roundEnv.errorRaised() && !roundEnv.processingOver()) {
    processRound(annotations, roundEnv);
  }
  return false;
}

碰巧我也在处理一个自定义注释处理器&我想在我的注释处理器中使用上面的代码片段。

if (!roundEnv.errorRaised() && !roundEnv.processingOver()) {
    processRound(annotations, roundEnv);
}
return false;
if (!roundEnv.errorRaised()) {
    processRound(annotations, roundEnv);
}
return false;

但是我没有注意到处理器的行为有任何变化。我得到了!roundenv.errorread()检查,但我看不出!roundenv.processingover()有什么用。

我想知道在处理某个回合时使用roundenv.processingover()有用的用例。

共有1个答案

公孙嘉禧
2023-03-14

这两个检查都很重要,但是在同一个项目中同时运行多个注释处理器之前,您不会注意到它们的效果。听我解释。

当Javac由于任何原因导致编译失败时(例如,由于缺少类型声明或解析错误),它不会立即终止。相反,它将收集尽可能多的关于错误的信息,并试图以有意义的方式向用户显示这些信息。此外,如果存在注释处理器,并且错误是由缺少类型或方法声明引起的,Javac将尝试运行这些处理器并重试编译,希望它们生成缺少的代码。这就是所谓的“多轮编制”。

编译序列如下所示:

    null
// this would fail with compilation error in absence of Dagger2
// but annotation processor will generate the Dagger_DependencyFactory
// class during compilation
Dagger_DependencyFactory.inject(this);

有些人认为这种技术不可靠,因为它依赖于使用源代码中不存在的类,并且将源代码与注释处理紧密联系在一起(并且不能很好地用于IDE代码完成)。但是实践本身是合法的,并且按照Javac开发人员的意图工作。

那么,在您的问题中,所有这些与Spring的注释处理器有什么关系呢?

你问题中的代码有缺陷。

    null

对于processingover:

  1. 如果当前轮不是最后一轮(processingover返回false),尝试生成尽可能多的输出;忽略用户代码中缺少的类型和方法(假设其他注释处理器可能在接下来的几轮中生成它们)。但是仍然尝试尽可能多地生成,以防其他注释处理器可能需要它。例如,如果您在每个类上触发代码生成(使用@entity注释),您应该迭代这些类并尝试为每个类生成代码,即使以前的类有错误或缺少方法。就我个人而言,我只是在try-catch中包装每一个单独的生成单元,并检查processingover:如果是false,则忽略错误,并继续迭代注释和生成代码。这使得Javac可以通过运行代码直到完全满意来打破由不同注释处理器生成的代码之间的循环依赖关系。
  2. 如果当前轮不是最后一轮(processingover返回false),并且上一轮的一些注释没有被处理(每当由于异常而导致处理失败时,我都会记得它们),请重试处理这些注释。
  3. 如果当前轮是最后一轮(processingover返回true),则查看是否还有未处理的注释。如果是,则失败编译(仅在最后一轮中!)

上面的序列是使用processingover的预期方式。

一些注释处理器使用processingover有点不同:它们缓冲每一轮生成的代码,并在最后一轮将其写入filer。这允许解析对其他处理器的依赖关系,但阻止其他处理器查找由“小心”处理器生成的代码。这是一个有点令人讨厌的策略,但是如果生成的代码不打算在其他地方引用,我想这是可以的。

还有像上面提到的第三方Spring configuration Validator这样的注释处理程序:它们误解了一些事情,并以猴子和扳手的方式使用API。

为了更好地了解整个过程,安装Dagger2,并尝试在另一个注释处理器使用的类中引用Dagger生成的类(最好是以一种可以让该处理器解析它们的方式)。这将很快向您展示,这些处理器如何处理多轮编译。大多数都会使Javac异常崩溃。有些人会吐出数千个错误,填满IDE错误报告缓冲区,混淆编译结果。很少有人会正确地参与多轮编译,但如果失败,仍然会吐出大量错误。

回到最初的问题:由于Spring配置验证处理器不希望生成任何代码(希望我没有深入研究它),而是应该总是报告扫描配置中的所有错误,因此理想情况下它应该这样工作:忽略errorread并推迟配置扫描,直到processingover返回true:这将避免在多个编译轮中多次报告相同的错误,并允许注释处理器生成新的配置片段。

可悲的是,有问题的处理器看起来被遗弃了(自2015年以来没有提交),但作者在Github上很活跃,所以也许你可以向他们报告这个问题。

同时,我建议你从深思熟虑的注释处理器中学习,比如Google Auto、Dagger2或我的小研究项目。

 类似资料:
  • 问题内容: 在阅读 Java 中的自定义注释处理器的代码时,我注意到处理器方法中的这段代码: 碰巧我也在使用自定义注释处理器,所以我想在我的注释处理器中使用上面的代码段。 我以这种方式尝试了上面的代码: & 这条路: 但我没有注意到处理器行为的任何变化。我得到了支票,但看不到有什么用。 我想知道在处理特定回合时有用的用例。 问题答案: 这两项检查都很重要,但是直到在同一项目中一次运行多个注释处理器

  • 主要内容:使用Rem语句注释,注释使用::声明为创建的脚本添加注释或文档总是一个好习惯。 这是一个维护脚本用来理解脚本实际所做的事情所必需的注释。 例如,考虑下面这段没有注释形式的代码。 如果一个没有任何注释的脚本,普通人试图理解脚本,那么需要很多时间来理解脚本做些什么工作。 使用Rem语句注释 有两种方法可以在批处理脚本中创建注释; 一个是通过命令。 语句后的任何文本都将被视为注释,不会被执行。 以下是此声明的一般语法。 语法 其中是需要添

  • 需要注释处理器的帮助。我创建了一个简单的注释处理器,它使用@autoservice注释来检查注释的字段是否为最终字段。但它没有显示任何编译时错误。这是我的配置 注释: 注释处理器: pom文件: 测试文件:

  • 我正在使用注释处理器来处理方法参数的注释。 用于参数的注释类型有一个注释@参数 现在,当注释处理器运行时,我想检查参数注释()是否有参数注释。我通过执行以下代码来实现这一点。 由于某种原因,arg始终为空。是否有注释未返回的原因?

  • 我在编译使用我的注释处理器的代码时收到以下错误: 关于如何调试这个有什么提示吗?错误输出根本没有用处。有没有办法得到更详细的错误?

  • 问题内容: 我有一个名为@Pojo的自定义注释,可用于自动生成Wiki文档: 我这样使用它: 注释资源方法,以便注释处理器可以自动生成描述所需资源和类型的Wiki页面。 我需要在注释处理器中读取该字段的值,但出现运行时错误。 在我的处理器的源代码中,我有以下几行: 但实际的类不适用于处理器。我认为我需要一个替代品来代替实际课程。我不确定该怎么买。 我得到的错误是: 该是我的一个提到的一类注释。 不