Groovy seems to have some very unpleasant behavior associated with "Groovy Beans" and closures that can cause it to mask local variables in certain circumstances.
Is this known behavior and is there some documentation somewhere that details this stuff? I wasted a lot of time trying to figure out what wasn't working...
Consider the following code:
class TestClass {
def doIt(Closure closure) {
closure.setDelegate(this)
closure.call()
}
def getRevision() {
return "testclass revision"
}
}
def testIt() {
def revision = "testit revision"
println "1: " + revision + " (expect: testit)"
TestClass tester = new TestClass()
tester.doIt {
println "2: " + getRevision() + " (expect: testclass)"
}
println "3: " + revision + " (expect: testit)"
tester.doIt {
println "4: " + revision + " (expect: testit)"
revision = getRevision()
println "5: " + revision + " (expect: testclass)"
println "6: ${getRevision()} (expect: testclass)"
println "7: " + getRevision() + " (expect: testclass)"
}
// expect to have been set to testclass value in previous closure
println "8: " + revision + " (expect: testclass)"
tester.doIt {
println "9: ${getRevision()} (expect: testclass)"
println "10: " + getRevision() + " (expect: testclass)"
}
println "11: " + revision + " (expect: testclass)"
}
testIt()
Running this code produces the following output:
1: testit revision (expect: testit)
2: testclass revision (expect: testclass)
3: testit revision (expect: testit)
4: testit revision (expect: testit)
5: testit revision (expect: testclass)
6: testit revision (expect: testclass)
7: testit revision (expect: testclass)
8: testit revision (expect: testclass)
9: testclass revision (expect: testclass)
10: testclass revision (expect: testclass)
11: testit revision (expect: testclass)
My main problem is with 5/6/7. It seems that simply using the local revision
variable within the closure "hides" the getRevision()
method in the delegate and replaces it with a bean-style auto-generated getRevision()
to match the revision
"property". If I don't use the revision
variable, calls to getRevision()
do not invoke this bean behavior.
Any insight or links to documentation would be appreciated!
Groovy closures have a resolveStrategy
property that can be used to control the resolution order. The default strategy is to look-up the property from the "owning" object and only if it cannot be found there to use the delegate. I believe that setting this to DELEGATE_FIRST
will get the behavior you are expecting.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With