如何使用反射获取具有最后值的所有Groovy变量

时间:2015-08-27 08:36:14

标签: reflection groovy

我希望在我的groovy脚本中转储所有变量并显示所有值。

我想动态地这样做,因为我想通过 try / catch 包围我所有的巨型groovies。在 catch 部分中,我想使用stacktrace转储所有变量状态。代码应该是所有groovies的通用。

问题是 this.getBinding()。getVariables()没有返回正确的变量状态。

我制作了一个小脚本来说明情况:

def test1 = 1;
test1 = 2;

int test2 = 1;
test2 = 2;

test3 = 1;
test3 = 2;

def errLog=new File("c:/temp/groovy_debug.txt");   
errLog.append("--------------------------------------------------------" + "\n");
errLog.append("  Context ["+getBinding().getVariables()+" ] \n");
errLog.append("--------" + "\n") ;

执行后我得到一个非常奇怪的结果

--------------------------------------------------------
  Context [[[creationStackTrace= <not available>], test1:null, errLog:null, test2:null, test3:2] ] 
--------

这意味着声明的变量总是报告为null或第一次赋值,但对于非类型变量,它获取最后一个值。 我想得到所有变量的最后一种情况(值= 2)。

有可能得到它们吗?

1 个答案:

答案 0 :(得分:0)

Tim Yates'answer说明了为什么你在访问非全局变量时遇到困难。对于像您这样的简单案例,您只需要分配和声明,您可以使用访问者来收集结果,例如

import org.codehaus.groovy.ast.expr.*
import org.codehaus.groovy.ast.stmt.*
import org.codehaus.groovy.ast.*
import org.codehaus.groovy.control.*
import org.codehaus.groovy.classgen.*
import java.security.CodeSource

def scriptText = '''
def test1 = 1;
test1 = 2;

int test2 = 1;
test2 = 2;

test3 = 1;
test3 = 2;
'''

class VariableVisitor extends ClassCodeVisitorSupport {
    def vars = [:]
    void visitExpressionStatement(ExpressionStatement statement) {
        if (statement.expression instanceof BinaryExpression)
            vars.put(statement.expression.leftExpression.name, statement.expression.rightExpression.value)
        super.visitExpressionStatement(statement)
    }
    void visitReturnStatement(ReturnStatement statement) {
        if (statement.expression instanceof BinaryExpression)
            vars.put(statement.expression.leftExpression.name, statement.expression.rightExpression.value)
        super.visitReturnStatement(statement)
    }
    protected SourceUnit getSourceUnit() {
        return source;
    }
}
class CustomSourceOperation extends CompilationUnit.PrimaryClassNodeOperation {
    CodeVisitorSupport visitor
    void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
        classNode.visitContents(visitor)
    }
}
class MyClassLoader extends GroovyClassLoader {
    CodeVisitorSupport visitor
    protected CompilationUnit createCompilationUnit(CompilerConfiguration config, CodeSource source) {
        CompilationUnit cu = super.createCompilationUnit(config, source)
        cu.addPhaseOperation(new CustomSourceOperation(visitor: visitor), Phases.CLASS_GENERATION)
        return cu
    }
}

def visitor =  new VariableVisitor()
def myCL = new MyClassLoader(visitor: visitor)
def script = myCL.parseClass(scriptText)

assert visitor.vars == ["test1":2, "test2":2, "test3":2]

但是,如果你的脚本有更复杂的东西(比如条件赋值),你需要更复杂的东西。您需要实际运行脚本并收集结果。