If I have a closure attached to an expando and the closure references a value on the expando like so...
def e = new Expando()
e.val = 'hi'
e.doit = { println delegate.val }
e.doit()
It works fine. and prints 'hi'
If I call the closure with the long form
e.doit.call()
It throws an error
groovy.lang.MissingPropertyException: No such property: val for class: Script1
at Script1$_run_closure1.doCall(Script1.groovy:4)
at Script1$_run_closure1.doCall(Script1.groovy)
at Script1.run(Script1.groovy:6)
This happens because the delegate is changed from e to the script. Why? I thought that e.doit() and e.doit.call() are supposed to be the same.
I can change the delegate manually - like so
def e = new Expando()
e.val = 'hi'
e.doit = { println delegate.val }
e.doit.delegate=e;
e.doit.call()
Any ideas on how to skip the explicit setting of the delegate?
Yes, there is a better idea.
Refer Expando instance directly (instead of delegate) when you know you are having a closure(dynamic method) defined for the Expando
which is nothing but a dynamic bean. On the other hand, the same test would yield expected result when tested against a concrete class:
def e = new Expando()
e.val = 'hi'
e.doit = {
println delegate.class.name
"$e.val Joseph"
}
assert e.doit() == 'hi Joseph'
assert e.doit.call() == 'hi Joseph'
class Test{
String a
def printA = {
println delegate.class.name
"$delegate.a Joseph"
}
}
def test = new Test(a: 'hi')
assert test.printA() == 'hi Joseph'
assert test.printA.call() == 'hi Joseph'
Note system out from println
in both cases.