首页 > 解决方案 > 无法访问 groovy 闭包中的局部变量

问题描述

我正在使用 java 使用反射修改一些 groovy 代码。

原始的 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: No such property: 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”,并且注入的结果代码是否符合预期。

关于为什么这不起作用的任何想法?

标签: groovyreflectionabstract-syntax-tree

解决方案


推荐阅读