I’d like to highlight one of the changes that was made late last week and is now available in the nightlies relating to “dynamic properties”. This is a rather far-reaching change so we’d like to get some feedback from our wonderful users before this feature is finalised for the next release.
Gradle domain objects are extensible in a number of ways. The most lightweight being that new properties can be added on demand. While this feature has proven to be very convenient for storing global settings and for inline custom tasks (among other things), it has also proven to be just a little too risky. With this mechanism, it is easy to create a new property on an object simply by misspelling the name of an existing property.
As an example, it can be all too easy to do this:
compileJava {
classPath = configurations.compile
}
In this case we are trying to manually set the compile classpath when we compile our Java source. However, what we are really doing is creating a new property called ‘classPath’ and assigning the ‘compile’ configuration to it. This is going to have no effect whatsoever as the property that is used to specify the compile classpath is called “‘classpath’”. This can be a tricky and time consuming problem to track down.
For this and other reasons, we are deprecating what was known as “dynamic properties”. The new replacement, is what we are terming “extra properties”.
The two are not that different, except that creating extra properties requires a special namespace which makes it clear that you do not intend to set an existing property. Let’s take a look at how you might right a custom inline task now with dynamic properties:
task doStuff {
prop1 = "foo"
prop2 = "bar"
doLast {
println "$prop1 $prop2"
}
}
As of the latest nightlies, this will now produce deprecation warnings when creating the dynamic properties ‘prop1’ and ‘prop2’. The same code using “extra properties” now looks like this:
task doStuff {
ext.prop1 = "foo"
ext.prop2 = "bar"
doLast {
println "$prop1 $prop2"
}
}
Or…
task doStuff {
ext {
prop1 = "foo"
prop2 = "bar"
}
doLast {
println "$prop1 $prop2"
}
}
All extra properties must be created through the “‘ext’” namespace. Once extra properties have been created, they are available on the owning object (in this case the ‘Task’) and can be read and changed. It’s only the initial declaration that needs to be done via the namespace.
It’s quite common to create dynamic properties on the project object.
version = "1.0-SNAPSHOT" // not a dynamic property, is project.version
isSnapshot = version.endsWith("-SNAPSHOT") // dynamic property
if (isSnapshot) {
// do snapshot stuff
}
With the new mechanism this looks like:
version = "1.0-SNAPSHOT"
ext.isSnapshot = version.endsWith("-SNAPSHOT")
if (isSnapshot) {
// do snapshot stuff
}
This change solves the problem of property misspelling, as for the next few releases a deprecation warning will be issued when trying to set a property that does not exist. Dynamic properties will eventually be removed entirely, meaning that this will be a fatal error in future versions of Gradle.
Another more subtle benefit is that user added properties are now clearly demarcated in the build configuration, making it easier to differentiate between added and provided functionality.
It’s also worth nothing that the “extra properties” mechanism is not to be used by plugins. That is, plugins should never populate the extra properties space as it is solely for “user” properties. Plugins should use the existing extension mechanism.
For more information and examples on the new “extra properties” mechanism, check out its documentation in the nightly builds.
If you have any thoughts or concerns you’d like to share about this change please leave replies below.