AST转换将整个方法体包装在一个闭包中

时间:2016-06-29 12:19:07

标签: groovy abstract-syntax-tree

我试图做一些相当简单的事情。我想将整个方法代码包装到另一个用于测量执行时间的闭包块中。现在我收到了一条非常有用的错误消息:

Error:Groovyc: NPE while processing Test.groovy

注释:

@Retention(RetentionPolicy.SOURCE)
@Target([ElementType.METHOD])
@GroovyASTTransformationClass(["WithTimingASTTransformation"])
public @interface WithTiming {
}

我的包装封口:

class Benchmark {
    static def measureTime(Closure cl) {
        def start = System.currentTimeMillis()
        def result = cl()
        def time = System.currentTimeMillis() - start
        println "it took $time"
        result
    }
}

我的转型:

@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
class WithTimingASTTransformation implements ASTTransformation {
    @Override
    void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
        MethodNode method = astNodes[1]
        method.code = wrap(method)
    }

    private Statement wrap(MethodNode method) {
        def newBlock = new BlockStatement()
        newBlock.addStatement(
                new ExpressionStatement(
                        new StaticMethodCallExpression(
                                new ClassNode(Benchmark),
                                'measureTime',
                                new ArgumentListExpression(
                                        new ClosureExpression(new Parameter[0], method.code)
                                ))))
        newBlock
    }
}

我真的被困在这里,不知道如何调试问题。

对类似主题有一个答案(将整个方法体包装到try / catch块here中)。这很好,但我的情况略有不同。

1 个答案:

答案 0 :(得分:0)

就我而言,类似的NPE来自:

java.lang.NullPointerException
    at org.codehaus.groovy.classgen.asm.ClosureWriter.createClosureClass(ClosureWriter.java:194)
    at org.codehaus.groovy.classgen.asm.ClosureWriter.getOrAddClosureClass(ClosureWriter.java:159)
    at org.codehaus.groovy.classgen.asm.ClosureWriter.writeClosure(ClosureWriter.java:90)
    at org.codehaus.groovy.classgen.AsmClassGenerator.visitClosureExpression(AsmClassGenerator.java:673)

鉴于:

    if (parameters == null || expression.getVariableScope() == null) {
        parameters = Parameter.EMPTY_ARRAY;
    } else if (parameters.length == 0) {
        // let's create a default 'it' parameter
        Parameter it = new Parameter(ClassHelper.OBJECT_TYPE, "it", ConstantExpression.NULL);
        parameters = new Parameter[]{it};
        Variable ref = expression.getVariableScope().getDeclaredVariable("it");
        if (ref != null) it.setClosureSharedVariable(ref.isClosureSharedVariable());
    }

和第194行(截至https://github.com/groovy/groovy-core/commit/a52d0d3c5dd1cbb342992d36235171718a563c8b)是:

Variable ref = expression.getVariableScope().getDeclaredVariable("it");

因此,您需要为ClosureExpression定义VariableScope。我必须在org.codehaus.groovy.ast.ClosureWriter中添加跟踪才能找到这个,因为类生成阶段的异常显示存在问题 - 无论是在IntelliJ Idea还是在Groovy Console中 - 它都没有显示正确的代码行

此外,我认为ClosureWriter或ClosureExpression构造函数可以修复为默认工作 - 没有这个NPE。我可能会向Groovy Jira提交一个问题。

现在我可以在我的代码中注入闭包表达式。但努力称之为关闭。

获得:

groovy.lang.MissingMethodException: No signature of method: com.a9ae0b01f0ffc.VSMSGEN.implementation.T_visa_recon_generator$_convert_vts_log_to_ctf_closure2.call() is applicable for argument types: () values: []