【问题标题】:How to get all Groovy variables with the last values using reflection如何使用反射获取具有最后一个值的所有 Groovy 变量
【发布时间】:2015-11-21 13:05:33
【问题描述】:

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

我想动态地执行它,因为我想用 try/catch 包围我所有的巨大 groovies。在 catch 部分,我想用堆栈跟踪转储所有变量状态。代码应该对所有 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)。

有可能得到它们吗?

【问题讨论】:

  • 我的结果(在临时文件中)不同:-------------------------------- ------------------------ 上下文 [[_outputTransforms:[groovy.ui.OutputTransforms$_loadOutputTransforms_closure1@27a97cea, groovy.ui.OutputTransforms$_loadOutputTransforms_closure2@5d4803d2, groovy.ui.OutputTransforms$_loadOutputTransforms_closure3@7f10fc0a, groovy.ui.OutputTransforms$_loadOutputTransforms_closure4@517b5471, groovy.ui.OutputTransforms$_loadOutputTransforms_closure5@3dd93c98], _:null, __:[], args:[], test3:2]] -------- 这是完整的代码,还是更大项目的一部分?
  • (limtt of length) 我的结果来自 Groovy 控制台。你还记得吗,那个 groovy 的“脚本”是 Script 类中“run()”的隐藏实现?
  • 这是完整的脚本,但它在另一个软件中进行了评估。当我尝试使用 this.getClass().getMethods() 列出所有方法时,我看到了很多方法。
  • 这些是“Java 方式”的方法,每个官方的 groovy 对象/类都有很多。如果我理解,您的问题是关于局部变量(??????)。看这里stackoverflow.com/questions/216484/…
  • 我想获取所有变量:本地、全局、静态、是否定义

标签: reflection groovy


【解决方案1】:

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]

但是,如果您的脚本包含更复杂的内容(例如条件赋值),您将需要更复杂的内容。您需要实际运行脚本并收集结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-09
    • 2022-01-06
    • 2019-05-23
    • 1970-01-01
    • 2012-01-28
    • 2016-03-30
    • 2017-07-10
    • 2018-04-17
    相关资源
    最近更新 更多