Java Mailing List Archive

http://www.gg3721.com/

Home » eclipse-plugin-dev.groovy »

[groovy-eclipse-plugin-dev] Type Safe Method Name Reflection AST

Jason Cheatham

2013-02-22

Replies: Find Java Web Hosting

Author LoginPost Reply

Hello all,

I want to be able to have a type safe way to get the name of a method as a String.

Given this class:

@AddMethodNamesAsStringFields(annotatedWith = "test.annotations.PropertyMethod")
class TestingAST {
    @PropertyMethod
def methodToRun() {
}

I've written an AST that will add a static final String field that matches the method name like this:
class TestingAST {
public static final String methodToRun = "methodToRun"

The goal is to then use the IDE's code assist to get the String:
TestingAST.methodToRun

The AST Transformation code is at the bottom.  Originally I had written the code in Groovy and it didn't work in the project, but when I wrote it in Java then it works fine within Eclipse.  However the IDE code assist completion doesn't work.  Is it possible to get the IDE to recognize the TestingAST.methodToRun field?

I'm using the Groovy Eclipse plugin and groovy-eclipse-compiler for maven.  There seems to be a new capability of the eclipse plugin to selectively allow some ast transforms to run during reconciling that may work.  I'm not sure exactly where to set this, though.  Should I set it in the pom.xml here?  
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<encoding>UTF-8</encoding>
<compilerId>groovy-eclipse-compiler</compilerId>
                <verbose>false</verbose>
</configuration>


http://jira.codehaus.org/browse/GRECLIPSE-1406
New compiler option that can be set like other java compiler options.
In CompilerOptions:
String OPTIONG_GroovyTransformsToRunOnReconcile = "org.eclipse.jdt.core.compiler.groovy.groovyTransformsToRunOnReconcile";
which can be initialized from a system property if not being set by another means:
greclipse.transformsDuringReconcile

I appreciate any help, thanks,
Jason

@AddMethodNamesAsStringFields(annotatedWith = "test.annotations.PropertyMethod")
class TestingAST {

static main(args) {
TestingAST t = new TestingAST();
        t.methodToRun();
        assert TestingAST.methodToRun == "methodToRun"
        assert TestingAST.otherMethod == "otherMethod"
        println TestingAST.methodToRun
        println TestingAST.otherMethod
}
    @PropertyMethod
def methodToRun() {

println "ran method methodToRun()"
}
    @PropertyMethod
    def otherMethod() {
        println "ran method otherMethod()"
    }
}

package test.annotations
Retention(RetentionPolicy.RUNTIME)
@Target(value = [ElementType.METHOD, ElementType.TYPE])
public @interface PropertyMethod {
}

package test.ast;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@GroovyASTTransformationClass({"test.ast.AddMethodNamesAsStringFieldsASTTransformation"})
public @interface AddMethodNamesAsStringFields {
    String[] annotatedWith() default {};

}

@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
public class AddMethodNamesAsStringFieldsASTTransformation  extends AbstractASTTransformation {
    public void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
        if (astNodes==null || astNodes.length < 2) return;
        if (astNodes[0] == null || astNodes[1] == null) return;
        if (!(astNodes[0] instanceof AnnotationNode)) return;
        AnnotationNode annotationNode = (AnnotationNode)astNodes[0];
        if (annotationNode.getClassNode() == null || (!annotationNode.getClassNode().getName().equals(AddMethodNamesAsStringFields.class.getName()))) return;

        ClassNode classThatIsAnnotated = (ClassNode)astNodes[1];
        List<String> annotatedWith = getMemberList(annotationNode, "annotatedWith");
        List<String> methodNames = new ArrayList<String>();
        for(MethodNode methodNode: classThatIsAnnotated.getAllDeclaredMethods()) {

            for(AnnotationNode inspectAnnotation:methodNode.getAnnotations()) {
                if (inspectAnnotation != null) {
                    for(String annotationName : annotatedWith) {
                        ClassNode classNode = inspectAnnotation.getClassNode();
                        if (classNode != null && classNode.getName().equals(annotationName)) {
                            methodNames.add(methodNode.getName());
                        }
                    }
                }
            }
        }
        for(String methodName:methodNames) {

            classThatIsAnnotated.addField(new FieldNode(methodName, ACC_PUBLIC | ACC_FINAL | ACC_STATIC, ClassHelper.STRING_TYPE, classThatIsAnnotated, new ConstantExpression(methodName)));
        }

    }

}
©2008 gg3721.com - Jax Systems, LLC, U.S.A.