无法访问Groovy闭包内的局部变量

时间:2018-11-16 14:55:08

标签: groovy reflection abstract-syntax-tree

我正在使用Java通过反射来修改一些常规代码。

原始groovy代码的格式为:

void method() {
    A(processId);
    B();
}

我需要修改它以注入processId:

void callMethod() {
    int processId = rand();
    invokeMethod(
    {->
     A(processId);
     B();
    }, processId);
}

void invokeMethod(Closure closure, int processId) {
    doSomething(processId);
    closure.call();
}

注意:invokeMethod()是现有方法,不会被注入。

当我如上所述修改原始代码时,出现此错误: “ groovy.lang.MissingPropertyException:无此类属性:processId”

我尝试将“ callMethod”方法的variableScope设置为包括“ processId”变量作为DeclaredVariable。

作为参考,这是我用来执行此操作的代码:

private void wrapMethod(@NonNull MethodNode node)
    {
        VariableExpression var = new VariableExpression("processId", new ClassNode(Integer.class));
        var.setClosureSharedVariable(true);
        //Generate a statement that creates a processId
        Statement statement = GeneralUtils.declS(var, GeneralUtils.callThisX("getUUID"));

        ClosureExpression methodClosure = createMethodClosure(node);

        ArgumentListExpression args = createArgumentListExpression(methodClosure, 
                varX("processId"));

        MethodCallExpression method = GeneralUtils.callThisX("invokeMethod", args);

        BlockStatement newMethodCode = GeneralUtils.block(statement, GeneralUtils.stmt(method));
        newMethodCode.setVariableScope(methodClosure.getVariableScope().copy());

        //Just to be safe, modifying the scope of the node as well.
        VariableScope newScope = node.getVariableScope().copy();
        newScope.putDeclaredVariable(var);

        node.setCode(newMethodCode);
        node.setVariableScope(newScope);
    }

private ClosureExpression createMethodClosure(MethodNode node) {
        //Get code from within node to dump into a closure.
        BlockStatement block = (BlockStatement) node.getCode();

        //Setting closureScope and adding processId
        VariableScope closureScope = block.getVariableScope().copy();

        closureScope.getReferencedLocalVariablesIterator()
                    .forEachRemaining(x -> x.setClosureSharedVariable(true));
        Variable var = new VariableExpression("processId", new ClassNode(Integer.class));
        var.setClosureSharedVariable(true);
        closureScope.putDeclaredVariable(var);

        ClosureExpression methodClosure = GeneralUtils.closureX(block);
        methodClosure.setVariableScope(closureScope);
        return methodClosure;
    }

我已经验证了代码,以检查是否可以在invokeMethod()块中访问“ processId”,并且注入的结果代码是否符合预期。

关于为什么这种方法无效的任何想法?

0 个答案:

没有答案