gradle
最近,我想在Gradle项目中构建并应用本地ast转换。 虽然我可以找到几个有关如何编写转换的示例,但找不到完整的示例来显示完整的构建过程。 转换必须单独编译,然后放在类路径中,因此其源代码不能简单地放在Groovy源代码树的其余部分中。 这是使我绊倒了一段时间的细节。
我最初设置了一个单独的GroovyCompile任务来处理其余注释,然后再处理其余注释(摘自Gradle论坛上Peter Niederwieser的有用建议)。 在此可行的同时,要应用转换的一个更简单的解决方案是设置多项目构建。 主项目依赖于具有ast转换源文件的子项目。 这是一个最小示例的目录结构:
ast/build.gradle
ast构建文件ast/src/main/groovy/com/cholick/ast/Marker.groovy
标记界面ast/src/main/groovy/com/cholick/ast/Transform.groovy
AST转换build.gradle
主构建文件settings.gradle
项目层次结构配置src/main/groovy/com/cholick/main/Main.groovy
转化源
对于完整的工作源(具有简单的测试,没有*导入),请克隆https://github.com/cholick/gradle_ast_example
根build.gradle文件包含对ast项目的依赖项:
dependencies {
...
compile(project(':ast'))
}
根settings.gradle定义ast子项目:
include 'ast'
基础项目还具有src / main / groovy / com / cholick / main / Main.groovy,其中包含要转换的源文件。 在此示例中,我编写的ast转换将名为“ added”的方法添加到类中。
package com.cholick.main
import com.cholick.ast.Marker
@Marker
class Main {
static void main(String[] args) {
new Main().run()
}
def run() {
println 'Running main'
assert this.class.declaredMethods.find { it.name == 'added' }
added()
}
}
在ast子项目中,ast / src / main / groovy / com / cholick / ast / Marker.groovy定义一个接口来标记ast转换的类:
package com.cholick.ast
import org.codehaus.groovy.transform.GroovyASTTransformationClass
import java.lang.annotation.*
@Retention(RetentionPolicy.SOURCE)
@Target([ElementType.TYPE])
@GroovyASTTransformationClass(['com.cholick.ast.Transform'])
public @interface Marker {}
最后,ast转换类处理源类并添加一个方法:
package com.cholick.ast
import org.codehaus.groovy.ast.*
import org.codehaus.groovy.ast.builder.AstBuilder
import org.codehaus.groovy.control.*
import org.codehaus.groovy.transform.*
@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
class Transform implements ASTTransformation {
void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
if (!astNodes) return
if (!astNodes[0]) return
if (!astNodes[1]) return
if (!(astNodes[0] instanceof AnnotationNode)) return
if (astNodes[0].classNode?.name != Marker.class.name) return
ClassNode annotatedClass = (ClassNode) astNodes[1]
MethodNode newMethod = makeMethod(annotatedClass)
annotatedClass.addMethod(newMethod)
}
MethodNode makeMethod(ClassNode source) {
def ast = new AstBuilder().buildFromString(CompilePhase.INSTRUCTION_SELECTION, false,
"def added() { println 'Added' }"
)
return (MethodNode) ast[1].methods.find { it.name == 'added' }
}
}
感谢Hamlet D'Arcy提供的一个出色的AST转换示例,并感谢Peter Niederwieser在论坛上回答了我的问题。
翻译自: https://www.javacodegeeks.com/2014/09/using-gradle-to-build-apply-ast-transformations.html
gradle