Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
666 views
in Technique[技术] by (71.8m points)

print the closure definition/source in Groovy

Anyone who knows how the print the source of a closure in Groovy?

For example, I have this closure (binded to a)

def a = { it.twice() } 

I would like to have the String "it.twice()" or "{ it.twice() }"

Just a simple toString ofcourse won't work:

a.toString(); //results in: Script1$_run_closure1_closure4_closure6@12f1bf0
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

short answer is you can't. long answer is:
depending on what you need the code for, you could perhaps get away with

// file: example1.groovy
def a = { it.twice() }
println a.metaClass.classNode.getDeclaredMethods("doCall")[0].code.text
// prints: { return it.twice() }

BUT
you will need the source code of the script available in the classpath AT RUNTIME as explained in

groovy.lang.MetaClass#getClassNode()
"Obtains a reference to the original AST for the MetaClass if it is available at runtime
@return The original AST or null if it cannot be returned"

AND
the text trick does not really return the same code, just a code like representation of the AST, as can be seen in this script

// file: example2.groovy
def b = {p-> p.twice() * "p"}
println b.metaClass.classNode.getDeclaredMethods("doCall")[0].code.text
// prints: { return (p.twice() * p) }

still, it might be useful as it is if you just want to take a quick look

AND, if you have too much time on your hands and don't know what to do you could write your own org.codehaus.groovy.ast.GroovyCodeVisitor to pretty print it

OR, just steal an existing one like groovy.inspect.swingui.AstNodeToScriptVisitor

// file: example3.groovy
def c = {w->
  [1,2,3].each {
    println "$it"
    (1..it).each {x->
      println 'this seems' << ' somewhat closer' << ''' to the 
      original''' << " $x"
    }
  }
}
def node = c.metaClass.classNode.getDeclaredMethods("doCall")[0].code
def writer = new StringWriter()
node.visit new groovy.inspect.swingui.AstNodeToScriptVisitor(writer)
println writer
// prints: return [1, 2, 3].each({
//     this.println("$it")
//     return (1.. it ).each({ java.lang.Object x ->
//         return this.println('this seems' << ' somewhat closer' << ' to the 
      original' << " $x")
//     })
// })

now.
if you want the original, exact, runnable code ... you are out of luck
i mean, you could use the source line information, but last time i checked, it wasn't really getting them right

// file: example1.groovy
....
def code = a.metaClass.classNode.getDeclaredMethods("doCall")[0].code
println "$code.lineNumber $code.columnNumber $code.lastLineNumber $code.lastColumnNumber"
new File('example1.groovy').readLines()
... etc etc you get the idea.  

line numbers shuld be at least near the original code though


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...