我编写了自己的AST Transformation,它应该生成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.home.gag.usage.Example.getMyCounter()适用于参数类型:()值:[] 可能的解决方案:getCounter(),setCounter(int) 在org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:56) 在org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:51) 在org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45) 在org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108) 在org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112) 在ua.home.gag.usage.Example.main(Example.groovy:12) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) 在com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
答案 0 :(得分:2)
我认为问题出在您的checkNodes
方法中。此表达式nodes[1] instanceof ClassNode
的结果为false
,因为nodes[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-core
存储库 - 转到https://github.com/grails/grails-core/,输入t
并搜索ASTTransformation