ext and code block's meaning in the gradle file
Asked Answered
L

4

82
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?

Larson answered 11/2, 2014 at 8:20 Comment(1)
How are you calling the method ext()? Could you paste the full gradle file please?Cis
R
118

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.

Rossman answered 11/2, 2014 at 11:40 Comment(3)
Hi,peter.Do you which grammar does ext involved in groovy?Or it is only in grade grammar?@Peter NiederwieserImprobity
I would be great if some one can point me where can I find documentation on the use of "ext block", tks.Myriapod
@Myriapod docs.gradle.org/current/dsl/…Tynan
H
14

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:

  1. Modify the delegate property of the closure to point to an object that the closure properties/methods should act on.

  2. 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...

Hannigan answered 2/12, 2016 at 0:40 Comment(0)
H
4

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

Hartzog answered 26/2, 2018 at 21:27 Comment(1)
You don't need the myExt method in this example, like ext is the instance of the ExtraPropertiesExtension too.Formulary
C
0

You have to understand Closure delegation strategies and how they work in Groovy. By default, any property you access in the Closure will look to the enclosing class or enclosing closure in the case of nested closures. Both of these are referred to as the owner of the Closure in Groovy. If you notice, the error is complaining, as it should that the enclosing/owning class, Test in this case does not contain those properties.

groovy.lang.MissingPropertyException: No such property: springVersion for class: Test

Therefore you have to set the delegate property in the Closure to override the default delegation strategy. Incidentally, the Closure delegate is a powerful concept in Groovy around which DSL' (Domain Specific Language) are built. Hope this helps.

Charlettecharley answered 16/5 at 15:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.