AST Transformations
[ 190 ]
So we are expecting a new method to be added that prints the expected string. Not
very useful for now, but let's see how we implement this annotation using an AST
transformation. We will start out by declaring an interface for the PrettyPrint
annotation itself as follows:
import org.codehaus.groovy.transform.GroovyASTTransformationClass
import java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target
@Target([ElementType.TYPE])
@Retention(RetentionPolicy.SOURCE)
@GroovyASTTransformationClass(["PrettyBasicASTTransformation"])
public @interface PrettyBasic {
}
This annotation interface uses several annotations to the compiler itself, to associate a
transformation with the @PrettyBasic annotation. The @Target annotation tells the
compiler that this particular transformation operates on types, so the transformation
will only be applied to these AST nodes during compilation. The @RetentionPolicy
annotation tells the compiler whether to retain the annotation in the class after
compilation. Our transformation only applies to the compilation phase, so we use
RetentionPolicy.SOURCE to indicate that it should be discarded after compilation.
We associate the implementing PrettyBasicASTTransformation class using,
@GroovyASTTransformationClass.
The transformation class itself is in the following code. We use the
@GroovyASTTransformation annotation to indicate that this is a class that
implements an AST transformation and specify which compiler phase that the
transformation should be applied to. In this case, we will select CompilePhase.
SEMANTIC_ANALYSIS, which is the earliest phase that we can apply a local
transformation.
To implement a transformation, we overload the visit method of
GroovyASTTransformation. As you read the following code, you will notice the
first lines are all defensive. Historically, the AST transformation aspects of Groovy
have changed a lot from language version to version. This can make your AST
transformations a little brittle on language upgrades. The convention has therefore
evolved to defensively program around any assumptions you intend to make
about what part of the AST you will be handed. We expect that the second AST
node we are handed will be a ClassNode object, and we will be calling addMethod
on it so that we ensure that only invocations that contain the expected nodes
are transformed:
http://www.ebook3000.com