我写了我自己的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
我认为问题出在你的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