Hi,
At the moment, you can add properties to projects and tasks (and dependencies,
source sets, and a few other things) dynamically, simply by assigning a value
for the property:
someProp = 'value'
assert project.hasProperty('someProp')
jar.someProp = 'value'
assert jar.hasProperty('someProp')
This is all nice and convenient. However, it also causes some problems. Here
are some examples:
A typo in a property name:
jar {
basename = 'someValue' // should be baseName
}
This adds a new property 'basename' instead of setting the value of 'baseName'.
Instead, it probably should give you an error (and suggest that you try
'baseName' instead).
Another problem is when you use convention properties before you apply the
corresponding plugin:
sourceCompatibility = 1.6
apply plugin: 'java'
In this case, we end up with 2 properties called 'sourceCompatibility', each of
which is used in different places. This, of course, can be extremely confusing.
To me, this implicit definition of properties is a nasty source of confusion,
even to those who know Gradle well. I keep getting bitten by it, even now.
So, I'd like to get rid of it, and require instead that dynamic properties are
declared explicitly.
One question is how this should look. We already have one way to extend an
object, using the convention object mechanism. This works for both projects and
tasks:
class MyConfigBean {
String someProp
List<File> someOtherProp = []
File someFile() { .... }
}
convention.plugins.myproperties = new MyConfigBean()
// The properties and methods of MyConfigBean are mixed in as properties of the
project
someOtherProp << someFile()
println someProp
This is kind of interesting as a way to declare dynamic properties, for a few
reasons:
* Plugins and build scripts would use the same mechanism
* Bean properties can be annotated with all kinds of meta-data, such as
validation constraints, or mappings to command-line options.
* Bean properties can have javadoc attached, so that build documentation can be
generated.
* It allows both properties and methods to be defined.
* It works well for all types of objects which need to be extended.
* It could provide namespacing, as you could group related properties and
methods into separate classes.
The syntax is a little awkward, but might be good enough.
But perhaps it would be good to add some kind of convenience methods for
declaring properties.
One option, is to use a block to declare properties:
properties {
String someProp = 'default-value'
def otherProp
}
jar {
properties { def customProp = 7 }
}
Another option, which really only works for extending a project, is to use the
local variable definitions in the script:
String someProp = 'default-value'
def otherProp
assert project.hasProperty('someProp')
We could tackle this in two steps: first, make it easy to declare properties
and deprecate (and warn about) the use of undeclared properties. And later,
remove the ability to use undeclared properties.
Thoughts?
--
Adam Murdoch
Gradle Developer
http://www.gradle.org
CTO, Gradle Inc. - Gradle Training, Support, Consulting
http://www.gradle.biz