I was looking at the closure scopes and found the output counter intuitive, this code was in build.gradle
file
plugins {
id 'java'
}
sourceSets {
println 'source sets closure scopes this,owner, delegate'
println this.toString() // output: root project 'multigradle'
println owner.toString() // output: DynamicObject for SourceSet container
println delegate.toString() // output: SourceSet container
}
Why the owner
is not equal to this
, does gradle clone the closure?
PS : For anyone who will read it in future 'multigradle' is my gradle project name.
TL;DR;
Essentially within the gradle source there is a method something like this:
so when you call:
(which incidentally is the same as calling
sourceSets({ some code })
, just with the parens removed which is ok in groovy)"some code" is not executed immediately when the
sourceSets
method is called. Gradle can choose to execute it whenever they decide it's time. Specifically, they can (and do) configure things like owner and delegate before actually executing the closure.Longer version
Turns out the
sourceSets
method in yourbuild.gradle
file is actually added by plugins such as the java/kotlin/groovy plugins.As an example we can look at the java plugin and the DefaultJavaPluginConvention class which has the following code:
this is the method that gets called when you type
sourceSets { ... }
in yourbuild.gradle
file. It gets handed the closure and proceeds to hand it off to theconfigure
method of the source set container. Note that we have not executed the closure yet, we are just passing it around as a non-executed block of code.If we dig a little, we find the
configure
method in the AbstractNamedDomainObjectContainer class:(
SourceSetContainer
is an interface and the implementing class inherits fromAbstractNamedDomainObjectContainer
...this is the rightconfigure
method)Where the ConfigureUtil has the following code:
where the relevant part is the call to the groovy Closure rehydrate method which according to docs does the following:
Only on the last line of the
configureTarget
method does gradle callexecute
on the action created to represent the closure. So the execution of the closure is done after the owner, the delegate and the this pointer have been configured according to gradle needs.