Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy AST - Adding annotations at compilation

Tags:

groovy

I'm trying to dynamicly crate an annotation that will dynamicaly add an @XmlElement annotation to every field in a class using metaprogramming and AST. I'm having problems creating the annotations and applying them to the fields properly.

The code i have is formatted here: http://pastebin.com/60DTX5Ya

import javax.xml.bind.annotation.XmlElement

@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
class WebserviceAnnotationModifier implements ASTTransformation {
@Override
void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {

    if (!astNodes) return
    if (!astNodes[0] || !astNodes[1]) return
    if (!(astNodes[0] instanceof AnnotationNode)) return
    if (!(astNodes[1] instanceof ClassNode)) return
    ClassNode node = (ClassNode)astNodes[1]
    List fields = node.getFields()
    fields.each {FieldNode field ->
        field.addAnnotation(ClassHelper.make(new XmlElement.DEFAULT()));
    }
}
}

@Retention(RetentionPolicy.SOURCE)
@Target([ElementType.TYPE])
@GroovyASTTransformationClass(classes =[WebserviceAnnotationModifier])
public @interface WebresourceAnnotation{}

@WebresourceAnnotation
class TestPerson{
    String name;
    String lastName;
    int Age
}

Am i approaching this all wrong? The reason i do this is i have a domain that is still in the making and i'd like to just go in and apply the annotation to all fields. Couldn't find any examples of annotations added during compilation. Is this not possible?

like image 440
Elotin Avatar asked Jan 24 '13 17:01

Elotin


1 Answers

Writing codes using Groovy AST Transformation alone does not work with the Grails reloading mechanism. Here's a proper way to implement AST transformation for a Grails app.

  1. Your transformer class must extends AbstractGrailsArtefactTransformer.
  2. Your transformer class must be annotated by @AstTransformer.
  3. You class must be put under org.codehaus.groovy.grails.compiler or its sub-package. In my case I use org.codehaus.groovy.grails.compiler.zk and it's working fine.
  4. Implement shouldInject() to match only classes you want, in this case domain classes.
  5. Override performInjection() and write your codes there.
  6. Pack your transformer and releated classes into a .jar file, or Grails compiler does not load it.
like image 155
chanwit Avatar answered Sep 22 '22 08:09

chanwit