Java 如何配置Gradle';使用注释处理器的增量构建

Java 如何配置Gradle';使用注释处理器的增量构建,java,gradle,querydsl,incremental-build,annotation-processor,Java,Gradle,Querydsl,Incremental Build,Annotation Processor,我想使用QueryDSL注释处理器作为构建过程的一部分。如何在每次更改任何类时消除不必要的注释处理器编译和运行?我希望QueryDSL仅在某些相关类更改时生成Q-*类 这种始终运行的注释处理器对构建过程时间有负面影响,如果必须运行注释处理器,则增量构建似乎不起作用 谢谢。AFAIK这目前是不可能的:请参阅本节“使用注释处理器进行增量编译”: …使用注释处理器,Gradle不知道将生成哪些文件。它也不知道在哪里以及基于什么条件。因此,如果正在使用注释处理器,Grade将禁用Java增量编译器 Gr

我想使用QueryDSL注释处理器作为构建过程的一部分。如何在每次更改任何类时消除不必要的注释处理器编译和运行?我希望QueryDSL仅在某些相关类更改时生成Q-*类

这种始终运行的注释处理器对构建过程时间有负面影响,如果必须运行注释处理器,则增量构建似乎不起作用


谢谢。

AFAIK这目前是不可能的:请参阅本节“使用注释处理器进行增量编译”:

…使用注释处理器,Gradle不知道将生成哪些文件。它也不知道在哪里以及基于什么条件。因此,如果正在使用注释处理器,Grade将禁用Java增量编译器

Gradle的相关问题:

博客文章还提到了一个可能的解决方法:

但是,可以将其影响限制在真正使用注释处理器的类集合中。简言之,您可以使用注释处理器声明不同的源代码集和不同的编译任务,并使其他编译任务不进行任何注释处理


然而,这似乎是一项相当艰巨的工作,所以我还没有使用它。

Gradle无法知道注释处理器使用哪些文件作为其输入,因此每次监视目录中的内容发生更改(src)时,它都必须触发完全重新编译

但是,您可以很容易地告诉Gradle哪些文件应该只触发注释处理。更改为其他文件不会触发注释处理器的使用,gradle可以使用其所有功能(例如增量构建)

我还添加了“强制”任务buildWithAP调用注释处理器,不管提示(启发式)函数结果如何

我的解决方案:

ext.isTask = { name -> return project.gradle.startParameter.taskNames.contains(name) }

/**
 * Heuristic function allowing to build process guess if annotation processor run is necessary
 * Annotation processors will not be called during build task if this function returns FALSE
 */
ext.isApInvalidated = { -> return hasAnyFileRelatedToApChanged() }

dependencies {
  if (isTask("buildWithAP") || isApInvalidated()) {
    println "Going to run annotation processors ..."
    apt "com.querydsl:querydsl-apt:$queryDslVersion:jpa"
  ...
  } else {
    // just add generated classes to the classpath
    // must be in else branch or multiple AP calls will collide!
  sourceSets.main.java.srcDirs += projectDir.absolutePath + "/build/generated/apt"
  } 
}

您可以使用任何您想要的注释处理器,例如您自己的,而不仅仅是QueryDSL


希望我的观点是明确的。

问题似乎已经解决了

谢谢,我也找到了那篇博文。遗憾的是,Gradle并没有通知开发人员跳过增量处理,因为注释处理器是有效的。但我找到了解决办法。看到我的答案了。不幸的是,它比这更复杂,但格拉德尔很快就会出版一本关于这个问题的著作。这项计划已在今年的格拉德尔峰会上宣布。您的解决方案是次优的,因为它会在需要注释处理时立即触发完整构建。在这种情况下,有价值的是增量注释处理。此外,确定是否应重新编译使用注释的文件的启发式方法过于简单,一些AP可能具有高级处理,并且很难识别这些文件。更不用说在大多数情况下,您需要对所有文件进行grep注释。即使您能够解决所有这些问题,您仍然需要对依赖项进行完整的依赖性分析,这样,如果触发AP的文件的传递闭包中的一个文件发生更改,它也会使文件本身无效(正如编译器所做的那样)。当然这不是最终的解决方案,但它也适用于我们的自定义AP和QueryDSL的解决方案。My HasAnyFileRelatedToAppChanged()只是基于文件更改时间戳比较。如果AP使用的文件真的更改,则会触发使用AP运行的完整构建。不过,这比每次触发它要好得多;)我期待着正式的解决方案,但目前这是我所想到的最好的解决方案。例如,我们遵循一种在实体文件上使用后缀*实体的常见做法。这些文件在大多数(或可能全部)情况下都是您只需关注更改的文件。如果更改,则触发QueryDSL的AP。如果没有,就别管它了。因此,对于querydsl,我们关注:
fileTree(dir:'src',include:'***Entity.java')
它可以工作,但这在很大程度上取决于AP的性质。如果AP不需要包含注释的文件以外的任何其他文件来执行其工作(即生成代码),那么是的,您的情况肯定更简单,您的解决方法可能会加快构建时间。因此,它与我的简单注释处理器一起工作,监视一个硬编码目录中的文件。每次跑步加速~2-3次!!希望Gradle能为所有注释处理器解决这个问题:)谢谢。很高兴它能为您工作。然而,我不认为Gradle可以普遍解决这个问题,因为它永远不知道AP需要哪些文件作为输入。
task buildWithAP (dependsOn: build) {}