【Groovy】编译时元编程 ( 利用注解进行 AST 语法树转换 | 定义注解并使用 GroovyASTTransformationClass 注明 AST 转换接口 | AST 转换接口实现 )

简介: 【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

image.png

目录
相关文章
|
9月前
|
SQL Java 编译器
在尝试使用Groovy编译器将一个字符串编译成一个类
在尝试使用Groovy编译器将一个字符串编译成一个类【1月更文挑战第22天】【1月更文挑战第109篇】
47 1
TypeScript-类和泛型和ypeScript-接口合并现象
TypeScript-类和泛型和ypeScript-接口合并现象
71 0
|
6月前
|
JSON JavaScript 前端开发
JS逆向 AST 抽象语法树解析与实践
JS逆向 AST 抽象语法树解析与实践
112 2
|
Python
学习Python语言的语法,例如函数、类、模块、循环中的类详解
学习Python语言的语法,例如函数、类、模块、循环中的类详解
76 1
|
Java Linux Android开发
【Groovy】编译时元编程 ( 编译时元编程引入 | 声明需要编译时处理的类 | 分析 Groovy 类的 AST 语法树 )
【Groovy】编译时元编程 ( 编译时元编程引入 | 声明需要编译时处理的类 | 分析 Groovy 类的 AST 语法树 )
187 0
【Groovy】编译时元编程 ( 编译时元编程引入 | 声明需要编译时处理的类 | 分析 Groovy 类的 AST 语法树 )
【Groovy】编译时元编程 ( ASTTransformation#visit 方法中访问 Groovy 类、方法、字段、属性 | 完整代码示例及进行编译时处理的编译过程 )(一)
【Groovy】编译时元编程 ( ASTTransformation#visit 方法中访问 Groovy 类、方法、字段、属性 | 完整代码示例及进行编译时处理的编译过程 )(一)
288 0
【Groovy】编译时元编程 ( ASTTransformation#visit 方法中访问 Groovy 类、方法、字段、属性 | 完整代码示例及进行编译时处理的编译过程 )(一)
【Groovy】编译时元编程 ( ASTTransformation#visit 方法中访问 Groovy 类、方法、字段、属性 | 完整代码示例及进行编译时处理的编译过程 )(二)
【Groovy】编译时元编程 ( ASTTransformation#visit 方法中访问 Groovy 类、方法、字段、属性 | 完整代码示例及进行编译时处理的编译过程 )(二)
193 0
【Groovy】编译时元编程 ( ASTTransformation#visit 方法中访问 Groovy 类、方法、字段、属性 | 完整代码示例及进行编译时处理的编译过程 )(二)
【Groovy】MOP 元对象协议与元编程 ( 使用 Groovy 元编程进行函数拦截 | 实现 GroovyInterceptable 接口 | 重写 invokeMethod 方法 )
【Groovy】MOP 元对象协议与元编程 ( 使用 Groovy 元编程进行函数拦截 | 实现 GroovyInterceptable 接口 | 重写 invokeMethod 方法 )
183 0
【Groovy】MOP 元对象协议与元编程 ( 使用 Groovy 元编程进行函数拦截 | 实现 GroovyInterceptable 接口 | 重写 invokeMethod 方法 )
|
Java
【Groovy】Groovy 动态语言特性 ( Groovy 中函数实参自动类型推断 | 函数动态参数注意事项 )
【Groovy】Groovy 动态语言特性 ( Groovy 中函数实参自动类型推断 | 函数动态参数注意事项 )
310 0
【Groovy】Groovy 动态语言特性 ( Groovy 中函数实参自动类型推断 | 函数动态参数注意事项 )
【Groovy】MOP 元对象协议与元编程 ( 使用 Groovy 元编程进行函数拦截 | 属性缺失 propertyMissing 函数回调 | 方法缺失 methodMissing 函数回调 )
【Groovy】MOP 元对象协议与元编程 ( 使用 Groovy 元编程进行函数拦截 | 属性缺失 propertyMissing 函数回调 | 方法缺失 methodMissing 函数回调 )
172 0
【Groovy】MOP 元对象协议与元编程 ( 使用 Groovy 元编程进行函数拦截 | 属性缺失 propertyMissing 函数回调 | 方法缺失 methodMissing 函数回调 )