Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get closure delegate to be used correctly when called within a Trait

Tags:

groovy

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?

like image 803
Renato Avatar asked Oct 30 '22 22:10

Renato


1 Answers

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
}
like image 161
Renato Avatar answered Jan 02 '23 21:01

Renato