AST转换
尽管你可能觉得通过扩展Groovy语法来实现新特性是不错的想法(就好像多路赋值一样),但大多数情况下我们不能仅通过增加新的关键字或是创建某些新的语法结构来表示新概念。然而借助于AST(Abstract Syntax Tree——抽象语法树)转换的想法,我们可以不用改变语法就能实现创新性的新想法。
在Groovy编译器编译Groovy脚本和类的过程中,源代码在内存中是以具体语法树的形式表现的,接下来被转换成抽象语法树。AST转换的目的在于让开发者可以介入到编译过程中,这样就可以在其转换成JVM可执行的字节码前对AST进行修改了。
AST转换为Groovy提供了改进的编译时元编程能力,这就在语言级别上提供了强大的灵活性而不会损失运行时性能。
有两种转换类型:全局转换与局部转换。
·编译器会在代码编译期间使用全局转换。加到编译器类路径中的JAR应该在META-INF/services/org.codehaus.groovy.transform.ASTTransformation处包含一个服务定位器文件,其中有一行给出了转换类的名字。转换类必须具有无参构造方法并实现org.codehaus.groovy.transform.ASTTransformation接口。它在编译期间会触及所有代码,因此请确保创建的转换器不会扫描所有的AST(因为这样做非常浪费时间)以保证编译的速度。
·局部转换是局部使用的,它是通过注解你想要转换的代码元素来实现的。为此,我们再次用到注解符号,这些注解应该实现org.codehaus.groovy.transform.ASTTransformation。编译器会发现注解并转换这些代码元素。
Groovy 1.6提供了几个局部转换注解,比如Groovy Swing Builder中用于数据绑定的@Bindable和@Vetoable、Grape模块系统中用于增加脚本库依赖的@Grab,还有一些不需要改变任何语法就可以支持的常规语言特性,如@Singleton、@Immutable、@Delegate、@Lazy、@Newify、@Category、@Mixin及@PackageScope。现在来看看这些转换吧(我们将在Swing增强一节中介绍@Bindable和@Vetoable,在Grape一节中介绍@Grab)。