Type Safe Method Name Reflection AST

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Type Safe Method Name Reflection AST

Jason Cheatham

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)));
        }

    }

}
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Type Safe Method Name Reflection AST

Andrew Eisenberg
Several things here:

1. In eclipse, you cannot consume an AST transform from the same
project that it is written in (unless you write the transform in
Java).  This could be the problem that you are having.

2. You can set the greclipse.transformsDuringReconcile as a system
property for all of Eclipse at startup (eg- in your eclipse.ini or
GGTS.ini add -Dgreclipse.transformsDuringReconcile=fully.qualified.name.to.Transform

The #2 feature is still experimental and we may provide more complete
access to the feature in future versions of Groovy-Eclipse.

On Fri, Feb 22, 2013 at 12:23 PM, Jason Cheatham <[hidden email]> wrote:

>
> 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)));
>         }
>
>     }
>
> }

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Type Safe Method Name Reflection AST

Jason Cheatham
Thanks Andrew for your help!  I implemented the AST Transform in Java and added the property to eclipse.ini:
-Dgreclipse.transformsDuringReconcile=test.ast.AddMethodNamesAsStringFields

Now if I have this:
@AddMethodNamesAsStringFields(annotatedWith = "test.annotations.PropertyMethod")
class TestingAST {
  @PropertyMethod
  def methodToRun() {
  }
  static main(args) {
TestingAST.
  }

In the TestingAST class, I can type:
"TestingAST." and code assist pops up with "methodToRun" as a static field!

However, if I have another class outside of TestingAST then code assist does not work for TestingAST.methodToRun.  Is there a way to solve this?

Thanks again,
Jason


From: Andrew Eisenberg <[hidden email]>
To: [hidden email]
Sent: Friday, February 22, 2013 6:16 PM
Subject: Re: [groovy-eclipse-plugin-dev] Type Safe Method Name Reflection AST

Several things here:

1. In eclipse, you cannot consume an AST transform from the same
project that it is written in (unless you write the transform in
Java).  This could be the problem that you are having.

2. You can set the greclipse.transformsDuringReconcile as a system
property for all of Eclipse at startup (eg- in your eclipse.ini or
GGTS.ini add -Dgreclipse.transformsDuringReconcile=fully.qualified.name.to.Transform

The #2 feature is still experimental and we may provide more complete
access to the feature in future versions of Groovy-Eclipse.

On Fri, Feb 22, 2013 at 12:23 PM, Jason Cheatham <[hidden email]> wrote:

>
> 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)));
>        }
>
>    }
>
> }

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email




Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Type Safe Method Name Reflection AST

Andrew Eisenberg
Any chance that you can share the project with me?  Best to do this in
a bug report.

I'll take a look.  In general, the transform must be available in
bytecode before it can be used.  The Groovy bytecode generation
happens slightly after the Java generation.  And that is why
transforms cannot be in Groovy and consumed in the same project.  I
wonder if there is some kind of ordering problem going on here as
well.

On Sun, Feb 24, 2013 at 9:06 AM, Jason Cheatham <[hidden email]> wrote:

> Thanks Andrew for your help!  I implemented the AST Transform in Java and
> added the property to eclipse.ini:
> -Dgreclipse.transformsDuringReconcile=test.ast.AddMethodNamesAsStringFields
>
> Now if I have this:
> @AddMethodNamesAsStringFields(annotatedWith =
> "test.annotations.PropertyMethod")
> class TestingAST {
>   @PropertyMethod
>   def methodToRun() {
>   }
>   static main(args) {
> TestingAST.
>   }
>
> In the TestingAST class, I can type:
> "TestingAST." and code assist pops up with "methodToRun" as a static field!
>
> However, if I have another class outside of TestingAST then code assist does
> not work for TestingAST.methodToRun.  Is there a way to solve this?
>
> Thanks again,
> Jason
>
> ________________________________
> From: Andrew Eisenberg <[hidden email]>
> To: [hidden email]
> Sent: Friday, February 22, 2013 6:16 PM
> Subject: Re: [groovy-eclipse-plugin-dev] Type Safe Method Name Reflection
> AST
>
> Several things here:
>
> 1. In eclipse, you cannot consume an AST transform from the same
> project that it is written in (unless you write the transform in
> Java).  This could be the problem that you are having.
>
> 2. You can set the greclipse.transformsDuringReconcile as a system
> property for all of Eclipse at startup (eg- in your eclipse.ini or
> GGTS.ini add
> -Dgreclipse.transformsDuringReconcile=fully.qualified.name.to.Transform
>
> The #2 feature is still experimental and we may provide more complete
> access to the feature in future versions of Groovy-Eclipse.
>
> On Fri, Feb 22, 2013 at 12:23 PM, Jason Cheatham <[hidden email]>
> wrote:
>>
>> 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)));
>>        }
>>
>>    }
>>
>> }
>
> ---------------------------------------------------------------------
> To unsubscribe from this list, please visit:
>
>     http://xircles.codehaus.org/manage_email
>
>
>
>

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Type Safe Method Name Reflection AST

Andrew Eisenberg
You can raise the bug report here: https://jira.codehaus.org/browse/GRECLIPSE

On Mon, Feb 25, 2013 at 8:17 AM, Andrew Eisenberg <[hidden email]> wrote:

> Any chance that you can share the project with me?  Best to do this in
> a bug report.
>
> I'll take a look.  In general, the transform must be available in
> bytecode before it can be used.  The Groovy bytecode generation
> happens slightly after the Java generation.  And that is why
> transforms cannot be in Groovy and consumed in the same project.  I
> wonder if there is some kind of ordering problem going on here as
> well.
>
> On Sun, Feb 24, 2013 at 9:06 AM, Jason Cheatham <[hidden email]> wrote:
>> Thanks Andrew for your help!  I implemented the AST Transform in Java and
>> added the property to eclipse.ini:
>> -Dgreclipse.transformsDuringReconcile=test.ast.AddMethodNamesAsStringFields
>>
>> Now if I have this:
>> @AddMethodNamesAsStringFields(annotatedWith =
>> "test.annotations.PropertyMethod")
>> class TestingAST {
>>   @PropertyMethod
>>   def methodToRun() {
>>   }
>>   static main(args) {
>> TestingAST.
>>   }
>>
>> In the TestingAST class, I can type:
>> "TestingAST." and code assist pops up with "methodToRun" as a static field!
>>
>> However, if I have another class outside of TestingAST then code assist does
>> not work for TestingAST.methodToRun.  Is there a way to solve this?
>>
>> Thanks again,
>> Jason
>>
>> ________________________________
>> From: Andrew Eisenberg <[hidden email]>
>> To: [hidden email]
>> Sent: Friday, February 22, 2013 6:16 PM
>> Subject: Re: [groovy-eclipse-plugin-dev] Type Safe Method Name Reflection
>> AST
>>
>> Several things here:
>>
>> 1. In eclipse, you cannot consume an AST transform from the same
>> project that it is written in (unless you write the transform in
>> Java).  This could be the problem that you are having.
>>
>> 2. You can set the greclipse.transformsDuringReconcile as a system
>> property for all of Eclipse at startup (eg- in your eclipse.ini or
>> GGTS.ini add
>> -Dgreclipse.transformsDuringReconcile=fully.qualified.name.to.Transform
>>
>> The #2 feature is still experimental and we may provide more complete
>> access to the feature in future versions of Groovy-Eclipse.
>>
>> On Fri, Feb 22, 2013 at 12:23 PM, Jason Cheatham <[hidden email]>
>> wrote:
>>>
>>> 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)));
>>>        }
>>>
>>>    }
>>>
>>> }
>>
>> ---------------------------------------------------------------------
>> To unsubscribe from this list, please visit:
>>
>>     http://xircles.codehaus.org/manage_email
>>
>>
>>
>>

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Loading...