I’m trying to migrate from Gradle 1.8 to 2.0 and noticed an intricate change in behavior of the DSL.
The following snippet demonstrates the change:
class SimpleDomainObject
{
String name
public SimpleDomainObject(String name)
{
this.name = name
}
void methodInSimpleDomainObject() {
println "methodInSimpleDomainObject called for object '$name'"
}
}
extensions.add('container', project.container(SimpleDomainObject))
container {
repositories {
methodInSimpleDomainObject()
}
}
println 'Objects in container: ' + container*.name
Executing this code in Gradle 1.8 prints:
methodInSimpleDomainObject called for object 'repositories'
Objects in container: [repositories]
Executing it in Gradle 2.0:
Build file 'build.gradle' line: 19
* What went wrong:
A problem occurred evaluating root project 'closurebinding'.
> Could not find method methodInSimpleDomainObject() for arguments [] on repository container.
This only occurs if the name of the domain object is a method in an enclosing closure delegate (like in this case the project). This is pretty suprising.
Digging through the changes, the culprit seems to be changes to ConfigureDelegate: http://code-review.gradle.org/changelog/Gradle/?cs=cf0af3757a35aed8801acccd5110d15935482058
Even more surprising: If you omit the call to methodInSimpleDomainObject, both versions yield the same result. But then there is no object created in the container!
Objects in container: []
I see, why the new behavior in Gradle 2.0 is more reliable than the behavior in 1.8. I’m still not convinced however, why one would want to call a configure-method, i.e. a method call with a single closure parameter, onto an object in some outer scope instead of creating a new object in the directly surrounding container.
Maybe you can reconsider and give the delegate precedence over the owner for all closure-like methods. If not, you should at least document this as potential breaking change in Gradle 2.0, as it is very hard to find and investigate.