文章目录

  • 1、一个简短故事
    • 1.1、生成字节码而不是源码
    • 1.2、开发者发挥生成代码的能力
  • 2、使得Groovy更简洁
    • 2.1、代码生成转换
    • 2.2、Class设计和设计模式注解
    • 2.3、日志提高
    • 2.4、声明并发
    • 2.5、容易克隆和扩展
    • 2.6、脚本支持
    • 2.7、更多转换
  • 3、探索AST
  • 4、创建ASTs
    • 4.1、亲手创建Ast
    • 4.2、AstBuilder.buildFromSpec
    • 4.3、AstBuilder.buildFromString
    • 4.4、AstBuilder.buildFromCode
  • 5、本地转换
  • 6、全局转换
  • 7、测试AST转换
  • 8、限制
  • 10、总结

AST- abstract syntax tree ( 抽象的语法树)

1、一个简短故事

1.1、生成字节码而不是源码

  • groovy自动生成getter,setter方法,变成字节码文件

1.2、开发者发挥生成代码的能力

2、使得Groovy更简洁

2.1、代码生成转换

  • @groovy.transform.ToString, 有点类似Lombok

    • /*** 使用groovy 的@ToString注解* @author liangchen* @date 2020/11/12*/
      class ToString91_92 extends GroovyTestCase{void testToStringToGenerating(){def sherLock = new Detective(firtName: "Sherlock", lastName: "Holmes")assert sherLock.toString() == 'com.jack.groovy.ch9.Detective(Sherlock, Holmes)'}void testToStringParameters(){def nancy = new Sleuth(firstName: 'Nancy',lastName: 'Drew')assert nancy.toString() == 'com.jack.groovy.ch9.Sleuth(firstName:Nancy, lastName:Drew)'// 忽略null值nancy.lastName=nullassert nancy.toString() == 'com.jack.groovy.ch9.Sleuth(firstName:Nancy)'}
      }
      @ToString
      class Detective{String firtName, lastName
      }//包括字段名且忽略null的字段
      @ToString(includeNames = true, ignoreNulls =true)
      class Sleuth{String firstName, lastName
      }
  • @EqualsAndHashCode

    • /*** @EqualAndHashCode* @author liangchen* @date 2020/11/12*/
      class EqualsAndHashCode93 extends GroovyTestCase {void testGeneratesEqualAndHashCodeMethods(){def magneto = new Actor(firstName: "Ian", lastName: "McKellen")def gandalf = new Actor(firstName: "Ian", lastName: "McKellen")assert  magneto == gandalf}
      }@EqualsAndHashCode
      class Actor{String firstName, lastName
      }
  • @TupleConstructor 构造方法(各种参数的构造方法)

    • /*** @TupleConstructor 生成各种参数的构造方法* @author liangchen* @date 2020/11/12*/
      class TupleConstructor94  extends GroovyTestCase{void testTupleConstructorToGenerateJava(){def al = new Athlete('Michael', 'Jordan')def a2 = new Athlete('Michael')assert al.firstName == a2.firstName}
      }@TupleConstructor
      class Athlete{String firstName, lastName
      }
  • @Lazy 延迟加载

    • /*** 延迟加载 @Lazy 并没有立即实例化,在使用时候才实例化* @author liangchen* @date 2020/11/12*/
      class Lazy95  extends  GroovyTestCase{void testLazyDelayProperty(){new ResourceMain().with {assert Resource.stats() == '1 alive, 0 used'res2.use()res3.use()res4.use()assert Resource.stats() == '4 alive, 3 used'assert res4 instanceof Resourcedef expected = 'res4=java.lang.ref.SoftReference'assert  it.dump().contains(expected)}}
      }class  Resource{private  static alive = 0private static used =0Resource(){alive++}def use(){used++}static stats(){"$alive alive, $used used"}
      }class ResourceMain{def rea1 = new Resource()@Lazy res2 = new Resource()@Lazy static res3 = {new Resource()}()@Lazy (soft = true) volatile  Resource res4
      }
      
  • @IndexedProperty List生成数组下标

    • /*** 类似生成数组的下标* @author liangchen* @date 2020/11/12*/
      class IndexedProperty96 extends GroovyTestCase{void testUsingIndexedProperty(){def books = ['The Mysterious Affair at Styles','The Murder at the Vicarage']new Author(name:'Agatha Christie', books:books).with {books[0] = 'Murder on the Orient Express'setBooks(0,'Death on the Nile')assert getBooks(0) == 'Death on the Nile'assert getBooks(1) =='The Murder at the Vicarage'}}
      }class Author{String name@IndexedProperty List<String> books
      }
  • @InheritConstructors 自动生成继承父类的构造方法

    • import groovy.test.GroovyTestCase/**** @author liangchen* @date 2020/11/12*/
      class InheritConstructors extends GroovyTestCase{void testInheritConstructors(){def pw1 = new MyPrintWriter(new File('out1.txt'))def pw2 = new MyPrintWriter('out2.txt', 'US-ASCII')[pw1, pw2].each {//将foo 字符写到 out1.txt和out2.txt文件中it << 'foo'//关闭流it.close()}//获取文本assert new File('out1.txt').text == new File('out2.txt').text// 删除文件['out1.txt','out2.txt'].each{new File(it).delete()}}}
      /*** 继承父类构造方法*/
      @groovy.transform.InheritConstructors
      class MyPrintWriter extends PrintWriter{}
      
  • @Sortable (排序)

    • import groovy.test.GroovyTestCase
      import groovy.transform.Sortable/*** @Sortable 注解,有序* @author liangchen* @date 2020/11/12*/
      class Sortable98  extends GroovyTestCase{void testSortableGenerateComparableMethod() {def politicians = [new Politician(first: 'Margaret', initial: 'H', last: 'Thatcher'),new Politician(first: 'George', initial: 'W', last: 'Bush'),new Politician(first: 'Jack', initial: 'O', last: 'Bush')]// 执行排序def sorted = politicians.toSorted()//执行排序之后调用initialsassert  sorted*.initials() == ['JOB','GWB',"MHT"]def byInitial = Politician.comparatorByInitial()sorted = politicians.toSorted(byInitial)assert sorted*.initials() == ['MHT','JOB', 'GWB']}
      }/*** 排序,首先根据last排序,然后按照initial 排序*/
      @Sortable(includes = 'last,initial')
      class Politician {String firstCharacter initialString lastString initials(){first[0] + initial + last[0]}
      }
  • @Builder注解 ,建造模式创建对象

    • /*** 建造模式创建对象, 链式调用* @author liangchen* @date 2020/11/12*/
      class Builder99  extends GroovyTestCase{void testNormalInstance(){def c = new Chemist(first: "jack", last: "mar", born: 1822)}void testUseBuilderInstance(){def builder = Chemist.builder()def c = builder.first('jack').last('mar').born(1867).build()assert c.first == 'jack'}
      }@Builder
      class Chemist{String first, lastint born
      }
      

2.2、Class设计和设计模式注解

  • @Canonical = @ToString, @EqualsAndHashCode, @TupleConstructor

    • import groovy.test.GroovyTestCase
      import groovy.transform.Canonical/*** 集合注解 @Canonical = @ToString, @EqualsAndHashCode, @TupleConstructor* @author liangchen* @date 2020/11/12*/
      class Canonical910 extends GroovyTestCase{void testCanonical(){def i1 = new Inventor('Thomas', 'Edison')def i2 = new Inventor('Thomas')assert i1 != i2assert i1.firstName == i2.firstNameassert i1.toString()=='com.jack.groovy.ch9.Inventor(Thomas, Edison)'}
      }
      @Canonical
      class Inventor{String firstName, lastName
      }
  • @Immutable (实例化后属性不能变更)

    • /*** 一旦实例化属性就不能修改* @author liangchen* @date 2020/11/12*/
      class Immutable911  extends GroovyTestCase{void testImmutable(){def g1 = new Genius(firstName: 'Albert',lastName: 'Einstein')assert g1.toString() == 'com.jack.groovy.ch9.Genius(Albert, Einstein)'def g2 = new Genius('Leonardo', 'da Vinci')assert g2.firstName == 'Leonardo'assert g1 != g2shouldFail (ReadOnlyPropertyException) {g2.lastName = 'DiCaprio'}}
      }@Immutable
      class Genius{String firstName, lastName
      }
  • @Delegate 委托能力

    • import groovy.test.GroovyTestCase/*** @Delegate 代理、委托* @author liangchen* @date 2020/11/12*/
      class NoisySet912 extends GroovyTestCase {void testDelegate(){Set ns = new NoisySet();ns.add(1)ns.addAll([2,3])assert ns.size() == 3}
      }/*** 如果某个类加了@Delegate,具有委托类能力*/
      class NoisySet {@DelegateSet delegate = new HashSet()@DelegateMap mapDelegate = new HashMap()@Overrideboolean add(item) {println "adding $item"delegate.add(item)}boolean addAll(Collection items) {items.each {println "adding $it"}delegate.addAll(items)}put(key,value) {mapDelegate.put(key, value) }}
  • @Singleton 单例

    • package com.jack.groovy.ch9import groovy.test.GroovyTestCase/*** @author liangchen* @date 2020/11/12*/
      class Single913 extends GroovyTestCase {void testSingletonInstance(){assert Zeus.instancedef ex = shouldFail (RuntimeException){new Zeus()}assert ex.toString()== "Can't instantiate singleton com.jack.groovy.ch9.Zeus. Use com.jack.groovy.ch9.Zeus.instance"}
      }@Singleton
      class Zeus{}
  • @Memoized 缓存方法结果

    • import groovy.test.GroovyTestCase
      import groovy.transform.Memoized/*** 缓存数据* @author liangchen* @date 2020/11/12*/
      class Memoized914 extends GroovyTestCase {void testMemoized(){new Calc().with {assert  sum(3,4) == 7assert sum(4,4) == 8//查询缓存assert  sum(3,4) == 7assert sum(4,4) == 8assert logs.join(" ") == "3+4 4+4"}}}class Calc {def logs = []@Memoizedint sum(int a, int b) {logs << "$a+$b"a + b}
      }
      
  • @TailRecursive 尾部递归,避免stack异常

    • import groovy.test.GroovyTestCase
      import groovy.transform.TailRecursive/*** @author liangchen* @date 2020/11/12*/
      class TailRecursive915 extends GroovyTestCase{void testTailRecursive(){assert ListUtil.reverse(['1','2','3']) == ['3','2','1']}}class ListUtil{static reverse(List list) {doReverse(list,[])}@TailRecursiveprivate static doReverse(List todo, List done) {if(todo.isEmpty()) doneelse doReverse(todo.tail(), [todo.head()] + done)}
      }

2.3、日志提高

  • 日志注解

    • /*** @Log注解* @author liangchen* @date 2020/11/12*/class Log916  extends GroovyTestCase{void testLog(){new Logs().search()}
      }
      @Log
      class Logs{def search(){log.fine(runLongDatabaseQuery())}def runLongDatabaseQuery() {println 'Calling database'return 'query result'}
      }
  • 其他注解

    • @Log @Commons @ Log4j @Log4j2 @Slf4j

2.4、声明并发

  • @Synchronized 同步 @WithReadLock 和@WithWriteLock (读锁和写锁)

    • package com.jack.groovy.ch9import com.beust.jcommander.IValueValidator
      import groovy.test.GroovyTestCase
      import groovy.transform.Synchronized
      import groovy.transform.WithReadLock
      import groovy.transform.WithWriteLock
      import groovy.util.logging.Log/*** @author liangchen* @date 2020/11/12*/
      class Synchronized917  extends GroovyTestCase{void testSynchronized(){def p1 = new PhoneBook1()(0..99).collect{num ->//开启一个线程Thread.start {p1.addNumber('Number' + num, '98765' + num)}//主函数等待}*.join()assert p1.getNumber('Number43') == '9876543'}void testCustomsSynchronized(){def p2 = new PhoneBook2()(0..99).collect{num ->Thread.start {p2.addNumber('Number' +num, '98765' + num)}}*.join()assert p2.getNumber('Number43') == '9876543'}void testReadAndWriteLock(){def p3 = new PhoneBook3()(3..4).collect{num ->Thread.start {sleep 100*nump3.addNumber('Number' +num, '98765' + num)}}(2..7).collect{count ->Thread.start {sleep 100 * countp3.getNumber('Number'+ count)}}*.join()}
      }class PhoneBook1{private final phoneNumbers = [:]@Synchronizeddef getNumber(key) {phoneNumbers[key]}@Synchronizedvoid addNumber(key, value) {phoneNumbers[key] = value}
      }/*** 自定义锁块*/
      @Log
      class PhoneBook2 {private final phoneNumbers = [:]private final lock = new Object[0]@Synchronized('lock')def getNumber(key) {phoneNumbers[key]}void addNumber(key, value) {log.info("Adding phone number $value")synchronized (lock) {phoneNumbers[key] = value}}
      }/*** 读写锁*/
      class PhoneBook3 {private final phoneNumbers = dummyNums()private dummyNums() {(1..8).collectEntries{['Number'+it, '765432' + it]}}@WithReadLockdef getNumber(key) {println "Reading started for $key"phoneNumbers[key]sleep 80println "Reading done for $key"}@WithWriteLockdef addNumber(key,value){println "Writing started for $key"phoneNumbers[key] = valuesleep 100println "Writing done for $key"}
      }

2.5、容易克隆和扩展

  • @AutoClone

    • import groovy.test.GroovyTestCase
      import groovy.transform.AutoClone
      import groovy.transform.AutoCloneStyle
      import groovy.transform.TupleConstructor/*** @AutoClone 克隆注解** @author liangchen* @date 2020/11/13*/
      class AutoClone720  extends GroovyTestCase{void testAutoClone(){def name = "Heston Blumenthal"def recipes =["Snail porridge","Bacon & egg ice cream"]def born = Date.parse("yyyy-MM-dd", '1999-01-01')def c1 = new Chef1( name,  recipes,  born)def c2 = c1.clone()assert  c2.recipes == recipesassert c1.name == c2.name}void testAutoCopyConstructor() {def name = 'Jamie Oliver'def recipes = ['Lentil Soup', 'Crispy Duck']def born = Date.parse('yyyy-MM-dd', '1975-05-27')def c1 = new Chef2(name, born, recipes)def c2 = c1.clone()assert c2.name == nameassert c2.born == bornassert c2.recipes == recipes}
      }/*** 提供四种类型, CLONE:不提供深度拷贝,不适合final修饰属性* SIMPLE : 只会调用无参构造方法,不支持深度拷贝* COPY_CONSTRUCTOR 不支持深度拷贝,支持final修饰属性* SERIALIZATION : 支持深度拷贝,不适合final修饰属性拷贝*/
      @AutoClone
      class Chef1{String  nameList<String> recipesDate born
      }@TupleConstructor
      @AutoClone(style=AutoCloneStyle.COPY_CONSTRUCTOR)class Person {final String namefinal Date born}@TupleConstructor(includeSuperProperties=true, callSuper=true)
      @AutoClone(style=AutoCloneStyle.COPY_CONSTRUCTOR)class Chef2 extends Person {final List<String> recipes}
      
  • @AutoExternalize

    • import groovy.test.GroovyTestCase
      import groovy.transform.ToString/*** @AutoExternal 序列化* @author liangchen* @date 2020/11/13*/
      class AutoExternalize922 extends GroovyTestCase{void testAutoExternalize() {def c = new Composer(name: 'Wolfgang Amadeus Mozart', born: 1756, married: true)//创建输出数组流def baos = new ByteArrayOutputStream()//写出流到baos中baos.withObjectOutputStream {os -> os.writeObject(c)}// 创建一个输入流def bais = new ByteArrayInputStream(baos.toByteArray())def loader = getClass().classLoaderdef resultbais.withObjectInputStream(loader) {result = it.readObject().toString()}assert result == 'com.jack.groovy.ch9.Composer(Wolfgang Amadeus Mozart, 1756, true)'}}@groovy.transform.AutoExternalize
      @ToString
      class Composer{String nameint bornboolean married
      }

2.6、脚本支持

  • @TimedInterrupt ( 超过时间打断)

    • /*** @author liangchen* @date 2020/11/13*/
      class TimedInterrupt923 extends GroovyTestCase{void testBlastOff1(){def b = new BlastOff1()Thread.start {try {b.countdown(10)} catch (TimeoutException ignore) {b.logs << 'aborted'}}.join()assert b.logs.join(' ') == '10 9 8 7 6 aborted'}
      }/*** 超过480毫米自动打断方法,触发timeInterrupt*/
      @TimedInterrupt(value = 480L,unit = TimeUnit.MILLISECONDS)
      class BlastOff1 {def logs = []def countdown(n) {sleep 100logs << nif (n == 0) {logs << 'ignition'}else countdown(n -1)}
      }
  • @ThreadInterrupt 线程打断

    • import groovy.test.GroovyTestCase
      import groovy.transform.ThreadInterrupt/*** 线程打断, 这里例子有问题* @author liangchen* @date 2020/11/13*/
      class ThreadInterrupt924 extends GroovyTestCase{void testThreadInterrupt(){def b = new BlastOff2()def t1 = Thread.start {try {println 1b.countdown(10)println 2} catch (InterruptedException ignore) {b.logs << 'aborted'}}sleep 300println 3t1.interrupt()t1.join()assert  b.logs.join(' ')=='10 9 8 7 6 5 4 3 2 1 0 ignition'}
      }@ThreadInterrupt()
      class BlastOff2 {def logs = []def countdown(n) {sleep 100logs << nif (n == 0) {logs << 'ignition'}else countdown(n -1)}
      }
  • @Field注解 脚本使用

    • import groovy.transform.Field/*** 不需要创建类似class文件结构只要是groovy就行*/
      @Field
      List awe = [1,2,3]
      def awesum(){awe.sum()
      }
      assert awesum() == 6
      
  • @BaseScript

2.7、更多转换

3、探索AST

  • 一般groovy编译和运行过程

4、创建ASTs

4.1、亲手创建Ast

  • 利用groovy已有AST的node创建新节点

    • import groovy.test.GroovyTestCase
      import org.codehaus.groovy.ast.ClassHelper
      import org.codehaus.groovy.ast.expr.ArgumentListExpression
      import org.codehaus.groovy.ast.expr.ConstructorCallExpressionimport org.codehaus.groovy.ast.stmt.ReturnStatementimport static org.codehaus.groovy.ast.ClassHelper.makeimport static org.codehaus.groovy.ast.tools.GeneralUtils.*
      /*** @author liangchen* @date 2020/11/13*/
      class Ast928 extends GroovyTestCase{void testCreateAst(){def ast = new ReturnStatement(new ConstructorCallExpression(ClassHelper.make(Date), ArgumentListExpression.EMPTY_ARGUMENTS))assert ast instanceof ReturnStatement//创建语法树返回再抽象def asts = returnS(ctorX(make(Date)))assert asts instanceof ReturnStatement}}

4.2、AstBuilder.buildFromSpec

  • 利用规范快速构架AST结构

    • /*** 利用AstBuilder 快速构建* @author liangchen* @date 2020/11/13*/
      class AstBuilder930  extends GroovyTestCase{void testAstBuilder(){def ast = new AstBuilder().buildFromSpec {returnStatement {constructorCall(Date){argumentList {}}}}assert ast[0] instanceof  ReturnStatement}
      }

4.3、AstBuilder.buildFromString

  • 利用字符串构建ast node

    • /*** 利用字符串直接创建Ast node* @author liangchen* @date 2020/11/13*/
      class AstBuildFromString931 extends GroovyTestCase{void testAstBuilderFromString(){def ast = new AstBuilder().buildFromString('new Date()')assert  ast[0] instanceof  BlockStatementassert ast[0].statements[0] instanceof  ReturnStatement}void testAstDynamicCode() {def approxPI = 3.14G// 直接添加方法,采用字符串def ast = new AstBuilder().buildFromString(CompilePhase.CLASS_GENERATION, false,'static double getTwoPI() { def pi = ' + approxPI + '; pi * 2 }')assert ast[1] instanceof  ClassNodedef method =ast[1].methods.find{it.name == 'getTwoPI'}assert method instanceof MethodNode}
      }

4.4、AstBuilder.buildFromCode

  • 利用code构建

    • /*** 利用code构建ast node* @author liangchen* @date 2020/11/13*/
      class AstBuildFromCode944  extends GroovyTestCase{void testAstBuildFromCode(){def ast = new AstBuilder().buildFromCode {//直接使用代码new Date()}assert  ast[0].statements[0]  instanceof  ReturnStatement}
      }

5、本地转换

  • 自定义main注解,自动生成main方法

    • package com.jack.groovy.ch9import org.codehaus.groovy.ast.*
      import org.codehaus.groovy.control.CompilePhase
      import org.codehaus.groovy.control.SourceUnit
      import org.codehaus.groovy.transform.ASTTransformation
      import org.codehaus.groovy.transform.GroovyASTTransformation
      import org.codehaus.groovy.transform.GroovyASTTransformationClassimport java.lang.annotation.ElementType
      import java.lang.annotation.Retention
      import java.lang.annotation.RetentionPolicy
      import java.lang.annotation.Target/*** 定义一下注解Main注解, 增加@GroovyASTransformationClass 表示这个注解处理的类* 是MainTransformation* RetentionPolicy 注解保持到源码阶段*/
      @Retention(RetentionPolicy.SOURCE)
      @Target([ElementType.METHOD])
      @GroovyASTTransformationClass(classes = [MainTransformation])
      @interface Main{}import static groovyjarjarasm.asm.Opcodes.ACC_PUBLIC
      import static groovyjarjarasm.asm.Opcodes.ACC_STATIC
      import static org.codehaus.groovy.ast.ClassHelper.VOID_TYPE
      import static org.codehaus.groovy.ast.tools.GeneralUtils.*// 确定那个时期处理,在指令选择处理
      @GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
      class MainTransformation implements ASTTransformation{// 定义默认节点private NO_EXCEPTIONS = ClassNode.EMPTY_ARRAYprivate STRING_ARRAY = ClassHelper.STRING_TYPE.makeArray()@Overridevoid visit(ASTNode[] astNodes, SourceUnit sourceUnit) {// 判断注解是否正确if(astNodes?.size() != 2) returnif(!(astNodes[0] instanceof  AnnotationNode)) returnif(astNodes[0].classNode.name != Main.name) returnif(!(astNodes[1] instanceof MethodNode)) return// 获取目标方法、目标类,目标实例def targetMethod = astNodes[1]def targetClass = targetMethod.declaringClassdef targetInstance = ctorX(targetClass)def callTarget = callX(targetInstance, targetMethod.name)def mainBody = block(stmt(callTarget))def visibility = ACC_STATIC | ACC_PUBLICdef parameters = params(param(STRING_ARRAY,'args'))//目标类增加main方法targetClass.addMethod('main', visibility, VOID_TYPE, parameters,NO_EXCEPTIONS, mainBody)}}
      new GroovyShell(getClass().classLoader).evaluate  """
      class Greeter{@com.jack.groovy.ch9.Maindef greet(){println "Hello from the greet() method!"}
      }
      """
      

6、全局转换

  • 这个暂时不懂, 有点类似dubbo services, spi

7、测试AST转换

  • GroovyClassLoader 和 GroovyShell

    • package com.jack.groovy.ch9import groovy.test.GroovyTestCase
      import groovy.transform.WithReadLockimport java.lang.reflect.Modifier
      import java.util.concurrent.locks.ReentrantReadWriteLock/*** ast 测试* @author liangchen* @date 2020/11/13*/
      class WithReadLockTestAst938 extends  GroovyTestCase{static class MyClass{@WithReadLockvoid readerMethod1(){}}void testLockFieldDefaultsForReadLock(){def dee =  MyClass.getDeclaredFields();def field = MyClass.getDeclaredField('$reentrantlock')assert Modifier.isPrivate(field.modifiers)assert !Modifier.isTransient(field.modifiers)assert Modifier.isFinal(field.modifiers)assert !Modifier.isStatic(field.modifiers)assert field.type == ReentrantReadWriteLock}/*** 这是类,不是实例*/void testLockFieldDefaultsForReadLocks(){//字符串 直接解析类def tester = new GroovyClassLoader().parseClass("""class MyClass{@groovy.transform.WithReadLockpublic void readerMethod1(){}}
      """)def field = tester.getDeclaredField('$reentrantlock')assert Modifier.isPrivate(field.modifiers)assert !Modifier.isTransient(field.modifiers)assert Modifier.isFinal(field.modifiers)assert !Modifier.isStatic(field.modifiers)assert field.type == ReentrantReadWriteLock}/*** groovyShell evaluate 是一个实例,而不是类*/void testLockFieldDefaultsForReadLockGroovyShell() {def tester = new GroovyShell().evaluate("""import groovy.transform.WithReadLockclass MyClass{@WithReadLockpublic void readerMethod1(){}}new MyClass()
      """)// 这里是getClass()def field = tester.getClass().getDeclaredField('$reentrantlock')assert Modifier.isPrivate(field.modifiers)assert !Modifier.isTransient(field.modifiers)assert Modifier.isFinal(field.modifiers)assert !Modifier.isStatic(field.modifiers)assert field.type == ReentrantReadWriteLock}}
  • @ASTTest

    • /*** @author liangchen* @date 2020/11/13*/@ASTTest(phase = CompilePhase.SEMANTIC_ANALYSIS, value={lookup('anchor').each{n-> assert n instanceof ForStatement}
      })
      void doSomenthing(){println "Hello, Groovy"anchor:for(int i=0; i<10; i++){println "Iteration $i"}
      }
      

8、限制

10、总结

  • 这一章有蒙圈,后面有需要再更新

第9章、编译期元编程和AST转换相关推荐

  1. 【Groovy】编译时元编程 ( 编译时方法注入 | 使用 buildFromSpec、buildFromString、buildFromCode 进行方法注入 )

    文章目录 一.在 MyASTTransformation#visit 方法中进行方法注入 1.使用 new AstBuilder().buildFromSpec 进行方法注入 2.使用 new Ast ...

  2. 【Groovy】编译时元编程 ( 编译时方法拦截 | 在 MyASTTransformation#visit 方法中进行方法拦截 )

    文章目录 一.在 MyASTTransformation#visit 方法中进行方法拦截 二.完整代码示例及进行编译时处理的编译过程 1.Groovy 脚本 Groovy.groovy 2.ASTTr ...

  3. 【Groovy】编译时元编程 ( 方法拦截时用到的 AST 语法树节点 MethodNode 节点 | MethodNode 节点分析 | MethodNode 节点中的BlockStatement)

    文章目录 一.方法拦截时用到的 AST 语法树节点 MethodNode 节点 二.MethodNode 节点分析 三.MethodNode 节点中的 BlockStatement 集合 一.方法拦截 ...

  4. 【Groovy】编译时元编程 ( ASTTransformation#visit 方法简介 | org.codehaus.groovy.ast.ModuleNode 脚本节点 )

    文章目录 一.ASTTransformation#visit 方法简介 二.org.codehaus.groovy.ast.ModuleNode 脚本节点 一.ASTTransformation#vi ...

  5. 【Groovy】编译时元编程 ( AST 语法树分析 | ClassNode 根节点 | 方法 Methods 节点 | 字段 Fields 节点 | 属性 Properties 节点 )

    文章目录 一.AST 语法树分析 一.AST 语法树分析 在上一篇博客 [Groovy]编译时元编程 ( 编译时元编程引入 | 声明需要编译时处理的类 | 分析 Groovy 类的 AST 语法树 ) ...

  6. 【Groovy】编译时元编程 ( 编译时元编程引入 | 声明需要编译时处理的类 | 分析 Groovy 类的 AST 语法树 )

    文章目录 一.编译时元编程引入 二.声明需要编译时处理的类 三.分析 Groovy 类的 AST 语法树 一.编译时元编程引入 在之前的 " [Groovy]MOP 元对象协议与元编程 &q ...

  7. 【Groovy】Groovy 语言特点简介 ( 支持 Java 语法 | 支持 Java 虚拟机 | Groovy 语言是动态语言 | Groovy 扩展 JDK | 编译时元编程 )

    文章目录 一.Groovy 支持 Java 语法 二.Groovy 支持 Java 虚拟机 三.Groovy 语言是 动态语言 四.Groovy 扩展 JDK 五.Groovy 编译时元编程 一.Gr ...

  8. Source Generator:C# 9 将迎来编译时元编程

    源码生成器(Source Generator)是 C#编译器的一个新特性,开发者可以使用编译器生成的元数据检查用户代码,并生成附加的源文件,与程序的其他部分一起编译. 受 F#类型提供程序的启发,C# ...

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

    文章目录 一.利用注解进行 AST 语法树转换 1.定义注解并使用 GroovyASTTransformationClass 注明 AST 转换接口 2.AST 转换接口实现 3.定义 Groovy ...

  10. 【Groovy】编译时元编程 ( ASTTransformation#visit 方法中访问 Groovy 类、方法、字段、属性 | 完整代码示例及进行编译时处理的编译过程 )

    文章目录 一.ASTTransformation#visit 方法中访问 Groovy 类.方法.字段.属性 二.完整代码示例及进行编译时处理的编译过程 1.Groovy 脚本 Groovy.groo ...

最新文章

  1. android系统属性获取及设置
  2. 博客阅读学习笔记-目录
  3. 【转】Web Reference和Service Reference的区别
  4. 每个tabpage中都有一个dategridview_每个女人,都有一个礼服梦
  5. WampServer无法直接打开myprojects的解决方法
  6. C++ 推断进程是否存在
  7. python 小兵(2)
  8. linux重启网卡命令_如何在 Linux 中更改 MAC 地址 | Linux 中国
  9. 【工赋开发者社区】产业互联网和工业互联网的区别
  10. 今天买了个黑莓7290
  11. Redis数据存储类型
  12. 《激荡三十年》十八、青春飞扬——互联网的崛起
  13. redis的原理和源码-数据持久化方式AOF的介绍和源码解析
  14. 借助WPS将Word文档转换为PPT文档
  15. 搭建个人网盘-owncloud
  16. 美翻你的朋友圈,Python生成蒙太奇马赛克图片
  17. opencv下载过慢的问题
  18. 招聘运维开发leader
  19. 千姿百态项目经理1——“苦逼”项目经理一
  20. 评论-ClickTracks 2.0

热门文章

  1. npm install时报sudo chown -R 501:20,如何解决
  2. 【UE入门指南】1 虚幻引擎 Unreal Engine 如何下载
  3. 初中学历计算机专业前景,初中毕业读成都计算机专业前景怎么样
  4. 工作中的感悟 (二) 交流与沟通的巨大作用
  5. java 循环语句编程练习
  6. 【软考之旅】网络层次与主要设备对应关系
  7. 版本管理+微建站+头条号接入-Zoomla!逐浪CMS2 x3.9.0发布
  8. Java面向对象四大特性
  9. android 56
  10. springboot 直接转发调用_SpringBoot系列: url重定向和转发