在 【Groovy】编译时元编程 ( 编译时方法拦截 | 在 MyASTTransformation#visit 方法中进行方法拦截 ) 博客中的 方法拦截的基础上进行方法注入 ;
首先对 MethodNode 进行处理
// 找到了 Student 下的 hello 方法
// 在 MethodNode 节点下调用
// it 就是 MethodNode 节点
BlockStatement blockStatement = code
// 清空 BlockStatement 中的 List<Statement> statements 成员
// 方法拦截清空 , 就不再执行原本的方法
// 方法注入不清空 , 会执行原来的方法内容
blockStatement.statements.clear()
如果将 blockStatement.statements
清理了 , 就不会再执行 Student#hello 原本的方法内容 ;
保留 blockStatement.statements
原来的集合元素 , 继续向其中添加其它元素 , 可以在原方法的基础上执行其它内容 ;
先创建方法节点 ,
// 创建方法节点
def methods = new AstBuilder().buildFromSpec {
expression {
methodCall {
variable('this')
constant('println')
argumentList {
constant('hello buildFromSpec')
}
}
}
}
然后将方法节点 , 添加到 blockStatement.statements
集合中 ;
// 将方法节点添加到 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)
class Student{
def name
def hello(){
println "hello"
}
}
def student = new Student()
student.hello()
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) {
println nodes
println source
println source.AST
println source.source.reader.text
// 获取 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)
}
}
}
创建 D:\002_Project\012_Groovy\Groovy_Demo\src\main\groovy\resources\META-INF\servicesorg.codehaus.groovy.transform.ASTTransformation
目录层级及文件 , 在文件中配置 ASTTransformation
实现类的全类名 :
MyASTTransformation
首先 , 进入 D:\002_Project\012_Groovy\Groovy_Demo\src\main\groovy
目录 ,
cd D:\002_Project\012_Groovy\Groovy_Demo\src\main\groovy
然后 , 编译 编译时处理类 MyASTTransformation.groovy , 将编译后的字节码文件 MyASTTransformation.class
保存到 D:\002_Project\012_Groovy\Groovy_Demo\src\main\groovy\classes
目录下 ,
groovyc -d classes MyASTTransformation.groovy
再后 , 打包上述编译好的字节码文件 , 存放在 D:\002_Project\012_Groovy\Groovy_Demo\src\main\groovy\test.jar
路径 ;
jar -cf test.jar -C classes . -C resources .
最后 , 依赖 test.jar 执行 Groovy.groovy 脚本
groovy -classpath test.jar Groovy.groovy
执行结果为 :
[org.codehaus.groovy.ast.ModuleNode@7d7758be]
org.codehaus.groovy.control.SourceUnit@2bdd8394
org.codehaus.groovy.ast.ModuleNode@7d7758be
class Student{
def name
def hello(){
println "hello"
}
}
def student = new Student()
student.hello()
[org.codehaus.groovy.ast.ModuleNode@16ce702d]
org.codehaus.groovy.control.SourceUnit@7b94089b
org.codehaus.groovy.ast.ModuleNode@16ce702d
println "hello buildFromString"
[org.codehaus.groovy.ast.ModuleNode@72c28d64]
org.codehaus.groovy.control.SourceUnit@6492fab5
org.codehaus.groovy.ast.ModuleNode@72c28d64
__synthesized__label__1644323893072__:{
println "hello buildFromCode"
}
hello buildFromCode