当前位置:网站首页>[groovy] compile time metaprogramming (compile time method injection | method injection using buildfromspec, buildfromstring, buildfromcode)

[groovy] compile time metaprogramming (compile time method injection | method injection using buildfromspec, buildfromstring, buildfromcode)

2022-07-06 00:35:00 Programmer community

List of articles

  • One 、 stay MyASTTransformation#visit Method injection
    • 1、 Use new AstBuilder().buildFromSpec Conduct method injection
    • 2、 Use new AstBuilder().buildFromString Conduct method injection
    • 3、 Use new AstBuilder().buildFromCode Conduct method injection
  • Two 、 Complete code examples and the compilation process of compile time processing
    • 1、Groovy Script Groovy.groovy
    • 2、ASTTransformation Interface implementation MyASTTransformation.groovy
    • 3、 To configure ASTTransformation
    • 3、 Use the command line for compile time processing

One 、 stay MyASTTransformation#visit Method injection


stay 【Groovy】 Compile time metaprogramming ( Compile time method interception | stay MyASTTransformation#visit Method interception in method ) Blog Method injection based on method interception ;

First of all, MethodNode To deal with

            //  eureka  Student  Under the  hello  Method             //  stay  MethodNode  Call under the node             // it  Namely  MethodNode  node             BlockStatement blockStatement = code            //  Empty  BlockStatement  Medium  List<Statement> statements  member             //  Method intercepts emptying  ,  No longer execute the original method             //  Method injection does not empty  ,  Will execute the original method content             blockStatement.statements.clear()

If you will blockStatement.statements Cleaned up , No more execution Student#hello The original method content ;

Retain blockStatement.statements The original set element , Continue adding other elements to it , Other contents can be executed on the basis of the original method ;

1、 Use new AstBuilder().buildFromSpec Conduct method injection

First create a method node ,

            //  Create a method node             def methods = new AstBuilder().buildFromSpec { 
                    expression { 
                        methodCall { 
                            variable('this')                        constant('println')                        argumentList { 
                                constant('hello buildFromSpec')                        }                    }                }            }

Then the method node , Add to blockStatement.statements Collection ;

            //  Add the method node to  hello  In the method             blockStatement.statements.addAll(methods)

2、 Use new AstBuilder().buildFromString Conduct method injection

            //  Create a method node             def methods2 = new AstBuilder().buildFromString('println "hello buildFromString"')            //  Add the method node to  hello  In the method             blockStatement.statements.addAll(methods2)

3、 Use new AstBuilder().buildFromCode Conduct method injection

            //  Create a method node ,  Note that what you get here is             def methods3 = new AstBuilder().buildFromCode { 
                    println "hello buildFromCode"            }            //  Add the method node to  hello  In the method             blockStatement.statements.addAll(methods3[0].statements)

Two 、 Complete code examples and the compilation process of compile time processing


1、Groovy Script Groovy.groovy

class Student{ 
        def name    def hello(){ 
            println "hello"    }}def student = new Student()student.hello()

 Insert picture description here

2、ASTTransformation Interface implementation MyASTTransformation.groovy

import org.codehaus.groovy.ast.ASTNodeimport org.codehaus.groovy.ast.builder.AstBuilderimport org.codehaus.groovy.ast.stmt.BlockStatementimport org.codehaus.groovy.control.SourceUnitimport org.codehaus.groovy.transform.ASTTransformationimport org.codehaus.groovy.transform.GroovyASTTransformation@GroovyASTTransformationclass MyASTTransformation implements ASTTransformation { 
        /** *  Compile time processing  * @param nodes AST  Abstract syntax tree node  ,  yes  ASTNode  An array type  * @param source  Source unit  ,  You can get the source file through this object  */    @Override    void visit(ASTNode[] nodes, SourceUnit source) { 
            println nodes        println source        println source.AST        println source.source.reader.text        //  obtain  Groovy.groovy  A collection of classes in a script  ,  And traverse         //  stay  ModuleNode  The class nodes in are encapsulated in the following members         // List<ClassNode> classes = new LinkedList<ClassNode>();        source.AST.classes.find { 
                //  The search name is  Student  Class             // it  yes  ClassNode  node             it.name == "Student"        }?.methods?.find { 
                //  lookup  Student  The name under the class is  hello  Methods             // it  yes  MethodNode  node             it.name == "hello"        }?.with { 
                //  eureka  Student  Under the  hello  Method             //  stay  MethodNode  Call under the node             // it  Namely  MethodNode  node             BlockStatement blockStatement = code            //  Empty  BlockStatement  Medium  List<Statement> statements  member             //  Method intercepts emptying  ,  No longer execute the original method             //  Method injection does not empty  ,  Will execute the original method content             blockStatement.statements.clear()            //  Create a method node             def methods = new AstBuilder().buildFromSpec { 
                    expression { 
                        methodCall { 
                            variable('this')                        constant('println')                        argumentList { 
                                constant('hello buildFromSpec')                        }                    }                }            }            //  Add the method node to  hello  In the method             //blockStatement.statements.addAll(methods)            //  Create a method node             def methods2 = new AstBuilder().buildFromString('println "hello buildFromString"')            //  Add the method node to  hello  In the method             //blockStatement.statements.addAll(methods2)            //  Create a method node ,  Note that what you get here is             def methods3 = new AstBuilder().buildFromCode { 
                    println "hello buildFromCode"            }            //  Add the method node to  hello  In the method             blockStatement.statements.addAll(methods3[0].statements)        }    }}

 Insert picture description here

3、 To configure ASTTransformation

establish D:\002_Project\012_Groovy\Groovy_Demo\src\main\groovy\resources\META-INF\servicesorg.codehaus.groovy.transform.ASTTransformation Directory level and documents , Configure... In a file ASTTransformation The full class name of the implementation class :

MyASTTransformation

 Insert picture description here

3、 Use the command line for compile time processing

First , Get into D:\002_Project\012_Groovy\Groovy_Demo\src\main\groovy Catalog ,

cd D:\002_Project\012_Groovy\Groovy_Demo\src\main\groovy

then , compile Compile time processing class MyASTTransformation.groovy , The compiled bytecode file MyASTTransformation.class Save to D:\002_Project\012_Groovy\Groovy_Demo\src\main\groovy\classes Under the table of contents ,

groovyc -d classes MyASTTransformation.groovy

And then , Package the above compiled bytecode file , Store in D:\002_Project\012_Groovy\Groovy_Demo\src\main\groovy\test.jar route ;

jar -cf test.jar -C classes . -C resources .

Last , rely on test.jar perform Groovy.groovy Script

groovy -classpath test.jar Groovy.groovy

The execution result is :

[org.codehaus.groovy.ast.ModuleNode@7d7758be]org.codehaus.groovy.control.SourceUnit@2bdd8394org.codehaus.groovy.ast.ModuleNode@7d7758beclass Student{ 
        def name    def hello(){ 
            println "hello"    }}def student = new Student()student.hello()[org.codehaus.groovy.ast.ModuleNode@16ce702d]org.codehaus.groovy.control.SourceUnit@7b94089borg.codehaus.groovy.ast.ModuleNode@16ce702dprintln "hello buildFromString"[org.codehaus.groovy.ast.ModuleNode@72c28d64]org.codehaus.groovy.control.SourceUnit@6492fab5org.codehaus.groovy.ast.ModuleNode@72c28d64__synthesized__label__1644323893072__:{ 
                    println "hello buildFromCode"            }hello buildFromCode

 Insert picture description here

原网站

版权声明
本文为[Programmer community]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202140223050398.html