0

I would like in my groovy script to dump all variables and display all values.

I would like to do it dynamically because I would like to surround all my huge groovies by a try/catch. In catch part I want to dump all variables state with the stacktrace. The code should be generic to all groovies.

The problem is that this.getBinding().getVariables() doesn't return the correct variable state.

I've made a small script to illustrate the situation:

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") ;

after the execution I get a very strange result

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

it means that the declared variables are always reported as null or as first assignment, but for not typed variables it get the last value. I would like to get the last situation for all variables (value=2).

Is it possible to get them?

Constantin
  • 71
  • 5
  • My result (in temp file) is different: -------------------------------------------------------- Context [[_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] ] -------- Is this complete code, or part of bigger project? – Jacek Cz Aug 27 '15 at 11:59
  • (limtt of length) my result is from Groovy Console. Do You remember, that groovy "script" is hidden implementation of "run()" in Script class ? – Jacek Cz Aug 27 '15 at 12:02
  • This is the full script but it's evaluated inside another software. When I tried to list all methods using this.getClass().getMethods() I see plenty of methods. – Constantin Aug 27 '15 at 13:41
  • these are method "in Java way", every officjal groovy object/class has many. Your question, if I understand, is about local variables (????). Look here http://stackoverflow.com/questions/216484/how-do-i-enumerate-all-the-defined-variables-in-a-groovy-script – Jacek Cz Aug 27 '15 at 14:33
  • I want to get all variables: local, global, static, def'ined or not – Constantin Aug 27 '15 at 14:50
  • I can confirm, strange. My groovy console show only test3 (variable not def'ined in any form) – Jacek Cz Aug 27 '15 at 15:07
  • As (quite) old programmer, I must understand,. You give me strong homework :) Say "in myown words", not defined variables are "in interpreter way", defined "in compiled way" Read answer by Ted http://stackoverflow.com/questions/184002/groovy-whats-the-purpose-of-def-in-def-x-0?answertab=votes#tab-top – Jacek Cz Aug 27 '15 at 15:21
  • Tiny observation: using Groovy from Java in more "object way" i.e. compile full class (not script) from GroovyClassLoader using un-defined variables is more restricted (gives evident error). I made short investigation, Binding context seems specific to script mode – Jacek Cz Sep 01 '15 at 13:49

1 Answers1

0

Tim Yates' answer illustrates why you're having difficulty accessing the non-global variables. For simple cases like yours, where you just have assignments and declarations, you can use a visitor to collect the results, like this

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]

However, if your script has more complicated stuff going on (like conditional assignments), you'll need something more sophisticated. You'd need to actually run the script and collect the results.

Community
  • 1
  • 1
Keegan
  • 11,345
  • 1
  • 25
  • 38