Groovy编译时元编程 ( 利用注解进行 AST 语法树转换 | 定义注解并使用 GroovyASTTransformationClass 注明 AST 转换接口 | AST 转换接口实现 )
Posted 韩曙亮
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Groovy编译时元编程 ( 利用注解进行 AST 语法树转换 | 定义注解并使用 GroovyASTTransformationClass 注明 AST 转换接口 | AST 转换接口实现 )相关的知识,希望对你有一定的参考价值。
文章目录
一、利用注解进行 AST 语法树转换
1、定义注解并使用 GroovyASTTransformationClass 注明 AST 转换接口
首先 , 定义 Compile 注解 , 该注解名称是任意字符串 , @Target(ElementType.METHOD)
表示该注解作用于方法上 , @GroovyASTTransformationClass("MyASTTransformation")
表示该注解修饰的节点对应的 AST 转换接口实现类是 MyASTTransformation
;
import org.codehaus.groovy.transform.GroovyASTTransformationClass
import java.lang.annotation.ElementType
import java.lang.annotation.Target
/**
* 该注解作用于方法上
*/
@Target(ElementType.METHOD)
@GroovyASTTransformationClass("MyASTTransformation")
@interface Compile
2、AST 转换接口实现
然后 , 实现 MyASTTransformation 类 , 该类继承 ASTTransformation 接口 ;
import org.codehaus.groovy.ast.ASTNode
import org.codehaus.groovy.ast.builder.AstBuilder
import org.codehaus.groovy.ast.stmt.BlockStatement
import org.codehaus.groovy.control.SourceUnit
import org.codehaus.groovy.transform.ASTTransformation
import org.codehaus.groovy.transform.GroovyASTTransformation
@GroovyASTTransformation
class MyASTTransformation implements ASTTransformation
/**
* 编译时处理方法
* @param nodes AST 抽象语法树节点 , 是 ASTNode 数组类型
* @param source 源单元 , 可以通过该对象拿到源文件
*/
@Override
void visit(ASTNode[] nodes, SourceUnit source)
// 获取 Groovy.groovy 脚本中的类集合 , 并进行遍历
// 在 ModuleNode 中的类节点封装在了如下成员中
// List<ClassNode> classes = new LinkedList<ClassNode>();
source.AST.classes.find
// 查找名称为 Student 的类
// it 是 ClassNode 节点
it.name == "Student"
?.methods?.find
// 查找 Student 类下名称为 hello 的方法
// it 是 MethodNode 节点
it.name == "hello"
?.with
// 找到了 Student 下的 hello 方法
// 在 MethodNode 节点下调用
// it 就是 MethodNode 节点
BlockStatement blockStatement = code
// 清空 BlockStatement 中的 List<Statement> statements 成员
// 方法拦截清空 , 就不再执行原本的方法
// 方法注入不清空 , 会执行原来的方法内容
//blockStatement.statements.clear()
// 创建方法节点
def methods = new AstBuilder().buildFromSpec
expression
methodCall
variable('this')
constant('println')
argumentList
constant('hello buildFromSpec')
// 将方法节点添加到 hello 方法中
//blockStatement.statements.addAll(methods)
// 创建方法节点
def methods2 = new AstBuilder().buildFromString('println "hello buildFromString"')
// 将方法节点添加到 hello 方法中
//blockStatement.statements.addAll(methods2)
// 创建方法节点, 注意此处拿到的是
def methods3 = new AstBuilder().buildFromCode
println "hello buildFromCode"
// 将方法节点添加到 hello 方法中
blockStatement.statements.addAll(methods3[0].statements)
3、定义 Groovy 类并使用 @Compile 注解修饰需要拦截的方法
最后 , 实现 Groovy 类 , 在该类的方法上使用 @Compile 注解 ;
class Student
def name
@Compile
def hello()
println "hello"
def student = new Student()
student.hello()
4、执行结果
执行上述 Groovy 脚本 , 执行结果为 :
hello
hello buildFromCode
以上是关于Groovy编译时元编程 ( 利用注解进行 AST 语法树转换 | 定义注解并使用 GroovyASTTransformationClass 注明 AST 转换接口 | AST 转换接口实现 )的主要内容,如果未能解决你的问题,请参考以下文章
Groovy编译时元编程 ( 编译时元编程引入 | 声明需要编译时处理的类 | 分析 Groovy 类的 AST 语法树 )
Groovy编译时元编程 ( ASTTransformation#visit 方法简介 | org.codehaus.groovy.ast.ModuleNode 脚本节点 )
Groovy编译时元编程 ( AST 语法树分析 | ClassNode 根节点 | 方法 Methods 节点 | 字段 Fields 节点 | 属性 Properties 节点 )
Groovy编译时元编程 ( 方法拦截时用到的 AST 语法树节点 MethodNode 节点 | MethodNode 节点分析 | MethodNode 节点中的BlockStatement)
Groovy编译时元编程 ( 编译时处理 ASTTransformation 接口实现 | 配置 ASTTransformation )