当前位置: 首页 > 知识库问答 >
问题:

Getter和Setter AST转换

双弘益
2023-03-14

我写了我自己的AST转换,它应该生成getter和setter方法(在这里创建getter方法)。但是他们不工作,不能理解原因。

使用属性创建注释

@Retention(RetentionPolicy.SOURCE)  
@Target([ElementType.FIELD])  
@GroovyASTTransformationClass(['ua.home.gag.ast.GetterAndSetterASTTransformation'])  
public @interface GetterAndSetter {  
}  

我的AST转换代码应该为注释字段创建getter方法

@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)  
class GetterAndSetterASTTransformation implements ASTTransformation {  

    @Override  
    void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {  
        if (!checkNodes(astNodes)) return  
            List fields = astNodes.findAll { it instanceof FieldNode }  
            fields.each {  
                MethodNode getter = getterMethod(ClassHelper.make(it));  
                it.declaringClass.addMethod(getter);  
        }  
    }  

    static def checkNodes(ASTNode[] nodes) {  
        nodes &&  
        nodes[0] &&  
        nodes[1] &&  
        nodes[0] instanceof AnnotationNode &&  
        nodes[0].classNode?.name == GetterAndSetter.class.name &&  
        nodes[1] instanceof ClassNode  
    }  

    private MethodNode getterMethod(FieldNode fieldNode) {  
        return new MethodNode(  
            "getMy" + fieldNode.name.capitalize(),  
            Modifier.PUBLIC,  
            new ClassNode(fieldNode.type),  
            new Parameter[0],  
            new ClassNode[0],  
            new BlockStatement(  
                [new ReturnStatement(  
                        new VariableExpression(fieldNode.name)  
                )],  
                new VariableScope())  
        )  
    }  
}

注释检查

import ua.home.gag.ast.GetterAndSetter  

class Example {  

    @GetterAndSetter  
    int counter = 5;  

    static void main(String[] args) {  
        println new Example().getMyCounter();  
    }
} 

在哪个地方我犯了错误?

运行结果:

线程“main”groovy中出现异常。lang.MissingMethodException:没有方法ua的签名。家插科打诨。用法实例getMyCounter()适用于参数类型:()值:[]可能的解决方案:getCounter(),组织上的setCounter(int)。科德豪斯。棒极了。运行时。脚本字节码适配器。在org上展开(ScriptBytecodeAdapter.java:56)。科德豪斯。棒极了。运行时。呼叫站点。PogoMetaClassSite。在org上调用(PogoMetaClassSite.java:51)。科德豪斯。棒极了。运行时。呼叫站点。CallSiteArray。org上的defaultCall(CallSiteArray.java:45)。科德豪斯。棒极了。运行时。呼叫站点。抽象调用站点。在org上调用(AbstractCallSite.java:108)。科德豪斯。棒极了。运行时。呼叫站点。抽象调用站点。在ua调用(AbstractCallSite.java:112)。家插科打诨。用法实例main(例如groovy:12)在sun。反映NativeMethodAccessorImpl。在sun上调用0(本机方法)。反映NativeMethodAccessorImpl。在sun上调用(NativeMethodAccessorImpl.java:57)。反映DelegatingMethodAccessorImpl。在java上调用(DelegatingMethodAccessorImpl.java:43)。朗。反思。方法在com上调用(Method.java:606)。intellij。rt.执行。应用阿普曼。main(AppMain.java:134)

PS回购https://bitbucket.org/maxrdev/ast-gands

共有1个答案

华永逸
2023-03-14

我认为问题出在你的check Nodes方法上。这个表达式节点[1]instanceof ClassNode计算为false,因为节点[1]instanceof FieldNode

您也不必过滤和迭代这些字段,因为这个转换将应用于所有用@GetterAndSetter注释的字段。这就是为什么您必须只关注注释字段的单个大小写。通常你要做的就是:

@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
class GetterAndSetterASTTransformation implements ASTTransformation {

    @Override
    void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
        AnnotationNode parent = (AnnotationNode) astNodes[0]
        FieldNode node = (FieldNode) astNodes[1]

        if (!(parent instanceof AnnotationNode) && !(node instanceof FieldNode)) {
            throw new RuntimeException("Internal error: wrong types: ${node.class} / ${parent.class}");
        }

        Statement statement = new BlockStatement([
                new ReturnStatement(new VariableExpression(node))
        ], new VariableScope())

        MethodNode methodNode = new MethodNode("getMy${node.name.capitalize()}",
                Modifier.PUBLIC,
                node.type,
                new Parameter[0],
                new ClassNode[0],
                statement
        )

        node.declaringClass.addMethod(methodNode)
    }
}

那么下面的代码将起作用:

class Example {

    @GetterAndSetter
    int counter = 5;

    @GetterAndSetter
    String lorem = 'asdasd'

    @Deprecated
    @GetterAndSetter
    BigDecimal ipsum = BigDecimal.ONE

    static void main(String[] args) {
        Example example = new Example()

        println example.getMyCounter()

        println example.getMyLorem()

        println example.getMyIpsum()
    }
}

结果是:

/usr/lib/jvm/java-1.8.0/bin/java -Didea.launcher.port=7541 -Didea.launcher.bin.path=/opt/idea-IU-129.1525/bin -Dfile.encoding=UTF-8 -classpath /usr/lib/jvm/java-1.8.0/jre/lib/resources.jar:/usr/lib/jvm/java-1.8.0/jre/lib/jsse.jar:/usr/lib/jvm/java-1.8.0/jre/lib/jce.jar:/usr/lib/jvm/java-1.8.0/jre/lib/charsets.jar:/usr/lib/jvm/java-1.8.0/jre/lib/management-agent.jar:/usr/lib/jvm/java-1.8.0/jre/lib/rt.jar:/usr/lib/jvm/java-1.8.0/jre/lib/ext/cldrdata.jar:/usr/lib/jvm/java-1.8.0/jre/lib/ext/dnsns.jar:/usr/lib/jvm/java-1.8.0/jre/lib/ext/sunpkcs11.jar:/usr/lib/jvm/java-1.8.0/jre/lib/ext/sunec.jar:/usr/lib/jvm/java-1.8.0/jre/lib/ext/zipfs.jar:/usr/lib/jvm/java-1.8.0/jre/lib/ext/localedata.jar:/usr/lib/jvm/java-1.8.0/jre/lib/ext/nashorn.jar:/usr/lib/jvm/java-1.8.0/jre/lib/ext/sunjce_provider.jar:/home/wololock/workspace/idea/ast-gands/target/classes:/home/wololock/.m2/repository/org/codehaus/groovy/groovy-all/2.3.7/groovy-all-2.3.7.jar:/opt/idea-IU-129.1525/lib/idea_rt.jar com.intellij.rt.execution.application.AppMain ua.home.gag.usage.Example
5
asdasd
1

Process finished with exit code 0

您可以在grails corerepository中找到更多示例-转到https://github.com/grails/grails-core/,键入t并搜索ASTTransformation

 类似资料:
  • 问题内容: 始终建议使用getter / setter访问私有变量。为什么最好将它们声明为public并对其进行访问。无论如何,我们正在使用getter和setter访问它? 问题答案: @mre的回答非常好,您的问题很重要。总结一下:您将对象的字段设置为私有,以控制其他对象使用它的方式。您的对象使用setter来: 限制和验证传递给设置器的数据 隐藏其内部数据结构(服务对其他对象感兴趣,而不是服

  • Kotlin自动生成它的getters和settings,但是我从来没有引用过它们?另外,用Kotlin编写自定义getter/setter的正确方法是什么?当我说< code>myObj.myVar = 99时,我感觉< code>myVar是我正在直接访问的< code>myObj的公共字段。这里到底发生了什么?

  • 有两种类型的对象属性。 第一种是 数据属性。我们已经知道如何使用它们了。到目前为止,我们使用过的所有属性都是数据属性。 第二种类型的属性是新东西。它是 访问器属性(accessor properties)。它们本质上是用于获取和设置值的函数,但从外部代码来看就像常规属性。 Getter 和 setter 访问器属性由 “getter” 和 “setter” 方法表示。在对象字面量中,它们用 get

  • 问题内容: 我现在有两个类:RemindersDAO.java和ViewLocalReminders.java。 我试图访问ViewLocalReminders.java中的变量,并且试图从RemindersDAO.java调用它。我通过使用getter / setter方法组合来做到这一点。但是,由于某种原因,我的变量值在getter方法中一直设置为0。这是代码: ViewLocalRemind

  • 问题内容: 我现在有两个类:RemindersDAO.java和ViewLocalReminders.java。 我试图访问ViewLocalReminders.java中的变量,并且试图从RemindersDAO.java调用它。我通过使用getter / setter方法组合来做到这一点。但是,由于某种原因,我的变量值在getter方法中一直设置为0。这是代码: ViewLocalRemind