You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Gradle多项目构建中全局AST转换未生效的解决问询

Gradle多项目构建中全局AST转换未生效的排查与解决

我正在尝试搭建一个Gradle多项目,将A项目中定义的全局AST转换应用到B项目的类上,但按照官方指南配置后并未生效。

项目结构

|- project-root
   |- settings.gradle
   |- A
      |-- build.gradle 
      |-- src
      └── main
          ├── groovy
          │   ├── gep
          │       └── WithLoggingASTTransformation.groovy
          └── resources
              └── META-INF
                  └── services
                      └── org.codehaus.groovy.transform.ASTTransformation
   |- B
      ├── build.gradle
      └── src
          └── main
              └── groovy
                 └── package1
                     └── Application.groovy

各配置文件代码

根项目settings.gradle

rootProject.name = 'test-global-ast'
include 'A'
include 'B'

A项目build.gradle

plugins {
    id 'groovy'
}

dependencies {
    implementation platform('org.apache.groovy:groovy-bom:4.0.5')
    implementation 'org.apache.groovy:groovy'
}

B项目build.gradle

plugins {
    id 'groovy'
    id 'application'
}

mainClassName = 'project1.App'

configurations { astTransformation }

dependencies {
    implementation platform('org.apache.groovy:groovy-bom:4.0.5')
    implementation 'org.apache.groovy:groovy'
    astTransformation project(':A')
}

tasks.withType(GroovyCompile).configureEach {
    astTransformationClasspath.from(configurations.astTransformation)
}

A项目WithLoggingASTTransformation.groovy

package gep

import groovy.transform.CompileStatic
import org.codehaus.groovy.ast.ASTNode
import org.codehaus.groovy.ast.expr.ArgumentListExpression
import org.codehaus.groovy.ast.expr.ConstantExpression
import org.codehaus.groovy.ast.expr.MethodCallExpression
import org.codehaus.groovy.ast.expr.VariableExpression
import org.codehaus.groovy.ast.stmt.BlockStatement
import org.codehaus.groovy.ast.stmt.ExpressionStatement
import org.codehaus.groovy.ast.stmt.Statement
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.control.SourceUnit
import org.codehaus.groovy.transform.ASTTransformation
import org.codehaus.groovy.transform.GroovyASTTransformation

@CompileStatic
@GroovyASTTransformation(phase= CompilePhase.SEMANTIC_ANALYSIS)
class WithLoggingASTTransformation implements ASTTransformation {

    @Override
    void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
        def methods = sourceUnit.AST.methods
        methods.each { method ->
            def startMessage = createPrintlnAst("Starting $method.name")
            def endMessage = createPrintlnAst("Ending $method.name")

            def existingStatements = ((BlockStatement)method.code).statements
            existingStatements.add(0, startMessage)
            existingStatements.add(endMessage)
        }
    }

    private static Statement createPrintlnAst(String message) {
        new ExpressionStatement(
                new MethodCallExpression(
                        new VariableExpression("this"),
                        new ConstantExpression("println"),
                        new ArgumentListExpression(
                                new ConstantExpression(message)
                        )
                )
        )
    }
}

A项目服务配置文件内容

gep.WithLoggingASTTransformation

B项目Application.groovy

package package1

class Application {

    def x() {
        println "x"
    }

    static void main(args) {
        println "hi"
        def a = new Application()
        a.x()
    }
}

当前现象

执行./gradlew :B:compileGroovy可正常编译,但执行./gradlew :B:run时,预期输出应包含AST转换添加的日志,实际仅输出:

hi
x
这说明全局AST转换未生效。

手动验证成功步骤

我通过以下步骤成功让全局AST转换生效:

  1. 执行./gradlew :A:jar将A项目打包为JAR
  2. 进入B目录:cd B
  3. 执行groovyc -cp A.jar:src/main/groovy/package1/ src/main/groovy/package1/Application.groovy编译B项目
  4. 执行java -cp groovy-4.0.13.jar:A.jar:. package1.Application运行编译后的类

同时修改了B项目的Application.groovy以匹配官方示例:

package package1

def x() {
    println "x"
}

x()

手动操作下AST转换生效了,但Gradle多项目构建中依然无法实现该效果,该如何调整配置?


解决方案

调整B项目的Gradle配置

  1. 修正主类路径:当前mainClassName = 'project1.App'是错误的,实际主类为package1.Application,需修改为:

    mainClassName = 'package1.Application'
    
  2. 正确配置AST转换类路径:Gradle的GroovyCompile任务需要明确加载A项目的编译产物(包括META-INF/services配置文件),修改B项目build.gradle:

    plugins {
        id 'groovy'
        id 'application'
    }
    
    mainClassName = 'package1.Application'
    
    dependencies {
        implementation platform('org.apache.groovy:groovy-bom:4.0.5')
        implementation 'org.apache.groovy:groovy'
        // 添加implementation依赖确保运行时可访问A项目类
        implementation project(':A')
    }
    
    tasks.withType(GroovyCompile).configureEach {
        // 直接引用A项目的JAR产物作为AST转换类路径
        astTransformationClasspath.from(project(':A').jar)
    }
    
  3. 清理并重新构建:执行命令清理旧产物并重新运行:

    ./gradlew clean :B:run
    

原理说明

全局AST转换依赖Groovy编译器在编译时读取META-INF/services下的配置文件,找到对应的转换类。之前的配置未正确传递A项目的资源文件,导致编译器无法发现全局转换规则。直接引用A项目的JAR产物,可确保编译器同时加载到转换类和服务配置文件。

内容的提问来源于stack exchange,提问作者Bioman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 04:11:07