Невозможно получить доступ к локальной переменной внутри Groovy замыкания - PullRequest
0 голосов
/ 16 ноября 2018

Я использую Java, чтобы изменить какой-то классный код, используя отражение.

Оригинальный заводной код в форме:

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"

Я пытался установить переменнуюScope метода "callMethod", чтобы включить переменную "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;
    }

Я проверил код, чтобы проверить, что 'processId' доступен в блоке invokeMethod () и что результирующий код из внедрения такой же, как и ожидалось.

Есть идеи, почему это не работает?

...