It happens because when you use the reflection based one (the x.class.methods.each
one), you concatenate and generate the code upon GString evaluation, which resolves only one variable against the current scope, which is arg
, and that is ok. If you print the code, it outputs a perfectly runnable Groovy code:
x = new Date()
x.class.methods.each { f ->
if (f.name.startsWith("get")) {
print "new Date()." + f.name + ": " + f.invoke(x)
println ''
}
}
In your second version, the GString
variables are resolved against the scope they were created, which is the script binding. So it tries to fetch the f
variable from that scope, and not from the code
variable. And that is why it crashes at the ${f}
variable.
If you change the code
variable into a plain string (single quotes), it won't resolve the variable arg
, and thus you will need to tweak a bit around it to create a new class from it. Even so, it will fail, unless you pass as argument groovy callAllMethods java.util.Date
, which is not groovy (pun intended).
So, to use your code in that way, the GString shouldn't be resolved in declaration time, but rather at evaluate()
time. Still, the arg
variable needs to be resolved in declaration time, thus, you need to concat it. Here is the result:
args.each { arg ->
println "Methods of ${arg} ..."
def code = '''
x = new '''+arg+'''()
x.class.methods.each { m ->
if (m.name.startsWith("get")) {
result = x."${m.name}"()
println "new '''+arg+'''().${m.name}: ${result}"
}
}
'''
evaluate code
println ''
}
Which, in my box (jdk7, groovy 2.1.3), outputs:
new Date().getDay: 0
new Date().getTimezoneOffset: 180
new Date().getDate: 2
new Date().getHours: 10
new Date().getMinutes: 39
new Date().getMonth: 5
new Date().getSeconds: 56
new Date().getTime: 1370180396136
new Date().getYear: 113
new Date().getClass: class java.util.Date
If you just want to output the properties from an object, may i suggest the object.properties
?
args.each { arg ->
println "Methods of ${arg} ..."
def code = '''
x = new '''+arg+'''()
x.properties.each {
println "new '''+arg+'''().${it.key}: ${x[it.key]}"
}
'''
evaluate code
println ''
}
It outputs a bit more stuff for Date
, though :-).