Reputation: 13690
I have a Groovy trait which needs to provide a config Closure as an argument to a library method call (it's HttpBuilder but it shouldn't matter).
For reproducing the issue, I created the following simple example:
trait T {
def doIt() {
return {
n = 1
}
}
}
class Delegate {
int n
}
class Tish implements T {
def go() {
def closure = doIt()
def d = new Delegate()
closure.delegate = d
closure()
assert d.n == 1
}
}
new Tish().go()
This is expected to run without errors because when the closure returned by the doIt()
method in the T
trait is run, its delegate is set to something that can set the n
variable to 1....
However, this does not work and I get this error:
groovy.lang.MissingPropertyException: No such property: n for class: Tish
If I make T
a class and let Tish
extend it instead, then it works!
I tried changing the Closure's delegate strategy but that did not help.
Is this a Groovy bug or is there a way to work around this issue?
Upvotes: 5
Views: 1149
Reputation: 13690
Alright, I found a workaround... Still, would be interesting to know if this is a bug, and if it is, when it will get fixed by the Groovy team!
UPDATE: this is a bug and hopefully will be fixed in a Groovy release in the near future!
All calls made within the config Closure can get the actual Delegate object by calling the getDelegate()
method, then setting all properties directly on it, like this:
return {
def d = getDelegate()
d.n = 1
}
Not ideal, but got me unstuck, hope it helps others...
EDIT: As pointed about by @bdkosher in the comments, another solution is to use setter syntax in the closure:
return {
setN 1
}
Upvotes: 2
Reputation: 1336
Change your code from
def d = new Delegate()
closure.delegate = d
closure()
to
def d = new Delegate()
closure.delegate = d
closure.run()
this solved a pretty similar issue, that i had with Grails 3.3.8, Groovy 2.4.15, Java 1.8.0_131. No idea why but it helped.
I was trying to chase down the error and added the following outputs
println this
println owner
println delegate
and figured out that in the first case delegate
was not changed even closure.delegate = d
was set before executing closure()
! If closure.run()
is called then delegate
was set correctly!?!
Upvotes: 0