最小的 gradle 多项目构建,包括全局 AST 转换

问题描述 投票:0回答:1

我正在尝试创建一个 gradle 项目,将项目 A 中定义的全局 AST 转换应用到项目 B 中定义的类。我一直按照本指南中的说明进行操作,但没有成功:

https://groovy-lang.org/metaprogramming.html#transforms-global

我的项目结构是:

|- 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)
}

B/gep/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/src/main/resources/META-INF/service/org.codehaus.groovy.transform.ASTTransformation

gep.WithLoggingASTTransformation

B/package1/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,我希望看到

开始主线

开始打印

打印结束

开始x

开始打印

x

打印结束

结局x

主要结局

然而,我却看到:

x

这让我相信全球 AST 并未得到应用。如何调整我的多项目构建,以便项目“A”中定义的全局 AST 成功应用于项目“B”中的类?

更新1

我能够通过

应用全局 AST
  1. 使用
    ./gradlew :A:jar
  2. 将项目 A 打包为 JAR
  3. 切换到B目录
    cd B
  4. 使用
    groovyc -cp A.jar:src/main/groovy/package1/ src/main/groovy/package1/Application.groovy
  5. 编译项目 B
  6. 使用
    java -cp groovy-4.0.13.jar:A.jar:. package1.Application
  7. 运行已编译的类

我还修改了 package1.Application 以更好地匹配 groovy-lang.org 中的示例:

B/package1/Application.groovy

package package1

def x() {
    println "x"
}

x()

通过这些更改,应用了全局 AST,但我仍然在努力让它在多项目构建中工作。

gradle groovy metaprogramming abstract-syntax-tree
1个回答
0
投票

事情似乎比我谷歌搜索建议的要简单。需要改变的主要内容是:

  1. 将对
    astTransformation
    配置的引用替换为
    implementation
    ,并删除配置 GroovyCompile AST 类路径的块

B/build.gradle

plugins {
    id 'groovy'
    id 'application'
}

mainClassName = 'project1.App'

dependencies {
    implementation platform('org.apache.groovy:groovy-bom:4.0.5')
    implementation 'org.apache.groovy:groovy'
    implementation project(':A')
}
  1. 将 AST 应用到示例中使用的相同代码(无包装类/主方法):
package package1

def x() {
    println "x"
}

x()

需要 2. 的原因是因为 WithLoggingASTTransformation 定义的 AST 转换应用于引用顶级方法的

sourceUnit.AST.methods
,而不是类内的方法。

通过这些更改

./gradlew :transformed:run
产生转换后的输出:

开始x

x

结局x

© www.soinside.com 2019 - 2024. All rights reserved.