ext and code block's meaning in the gradle file
ext {
springVersion = "3.1.0.RELEASE"
emailNotification = "[email protected]"
}
Above code is the snippet of build.gradle
I understand that call ext method with { } closure parameter. it's right? So I think gradle is accessing springVersion and emailNotification. I'm gonna verify my assumption with below code
def ext(data) {
println data.springVersion
}
ext {
springVersion = "3.1.0.RELEASE"
emailNotification = "[email protected]"
}
but run that code below Error occured.
groovy.lang.MissingPropertyException: No such property: springVersion for class: Test
do you explain ext and code block specifically?
ext
is shorthand for project.ext
, and is used to define extra properties for the project
object. (It's also possible to define extra properties for many other objects.) When reading an extra property, the ext.
is omitted (e.g. println project.springVersion
or println springVersion
). The same works from within methods. It does not make sense to declare a method named ext
.
Here is the explanation for why the sample code in the question produces an error.
In the code:
ext {
springVersion = "3.1.0.RELEASE"
emailNotification = "[email protected]"
}
Does not pass to the function "ext" an object that has the springVersion and emailNotification properties. The curly braces don't mean a POJO but a closure. This is why the "ext" function complains it can't get to the properties.
The idea with passing such a closure, known as a configuration closure, is that the receiving function will:
Modify the delegate property of the closure to point to an object that the closure properties/methods should act on.
execute the closure()
Thus the closure executes and when it refers to methods / properties these will be executed on the object to be configured.
Thus, the following modification to your code will make it work:
class DataObject {
String springVersion;
String emailNotification;
}
def ext(closure) {
def data = new DataObject() // This is the object to configure.
closure.delegate = data;
// need this resolve strategy for properties or they just get
// created in the closure instead of being delegated to the object
// to be configured. For methods you don't need this as the default
// strategy is usually fine.
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure() // execute the configuration closure
println data.springVersion
}
ext {
springVersion = "3.1.0.RELEASE"
emailNotification = "[email protected]"
}
Hope this helps. Groovy closures get some time getting used to...
It's the overriding of get() and set() by ExtraPropertiesExtension
that is the key to making the configuration syntax for never before defined properties work.
class DataObject {
HashMap<String, Object> props = new HashMap<String, Object>()
Object get(String name) {
return props.get(name)
}
void set(String name, @Nullable Object value) {
props.put(name, value)
}
}
def myExtInstance = new DataObject()
def myExt = { Closure closure ->
def data = myExtInstance
closure.delegate = data;
// need this resolve strategy for properties or they just get
// created in the closure instead of being delegated to the object
// to be configured. For methods you don't need this as the default
// strategy is usually fine.
closure.resolveStrategy = Closure.DELEGATE_FIRST
closure() // execute the configuration closure
println data.springVersion
}
myExt {
springVersion = "3.1.0.RELEASE"
emailNotification = "[email protected]"
}
println "myExtInstance.springVersion" + myExtInstance.springVersion
See ExtraPropertiesExtension docs