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转换生效:
- 执行
./gradlew :A:jar将A项目打包为JAR - 进入B目录:
cd B - 执行
groovyc -cp A.jar:src/main/groovy/package1/ src/main/groovy/package1/Application.groovy编译B项目 - 执行
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配置
修正主类路径:当前
mainClassName = 'project1.App'是错误的,实际主类为package1.Application,需修改为:mainClassName = 'package1.Application'正确配置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) }清理并重新构建:执行命令清理旧产物并重新运行:
./gradlew clean :B:run
原理说明
全局AST转换依赖Groovy编译器在编译时读取META-INF/services下的配置文件,找到对应的转换类。之前的配置未正确传递A项目的资源文件,导致编译器无法发现全局转换规则。直接引用A项目的JAR产物,可确保编译器同时加载到转换类和服务配置文件。
内容的提问来源于stack exchange,提问作者Bioman
相关产品推荐
相关产品推荐

