When to use `Property` for custom task?

The documentation for custom tasks just uses a private field and setter/getter combination for task properties. But the JavaExec task in gradle source code uses Property<String> for the mainClass task property (https://github.com/gradle/gradle/blob/f8d612ca6b1d21f79690800ceaf95c97b10ba0ac/subprojects/language-java/src/main/java/org/gradle/api/tasks/JavaExec.java#L114). What’s the advantage here? Should Property<T> be used for custom tasks?

1 Like

Property and Provider allow for lazy configuration whereby build authors can configure the source of the property before the actual value itself is known/configured.

You could support both styles of configuration with a convenience setter method

public class MyTask extends DefaultTask {
    @Input
    private final Property<String> property = getProject().getObjects().property(String)

    public Property getProperty() {
        return this.property;
    }

    public void setProperty(String value) {
        getProperty().set(value);
    } 

    @TaskAction
    public void doStuff() {
        String propertyValue = property.get();
        // do stuff with propertyValue 
    }
}

I’m not 100% sure if this is good advice, because this would violate the java beans spec (since the getter and setter are different types) which might confuse groovy

1 Like

In Groovy, setters and getters can differ in type. This is perfectly legal and Groovy will handle it:

  • When you use it as a setter, like, property = 'mystring', setProperty(String) is called.
  • When you use it as a getter, like, println(property), getProperty() with the Property return type is called.

However:

  • It can lead to type confusion. Someone reading your code might expect the property to always be a String. For different types, it could be better to call the function differently.
  • I know the name of the property is irrelevant for this example, but just to clarify, I don’t recommend using names like property, getProperty, setProperty, because it can confuse the reader, as the DefaultTask class already has the following functions:
    public Object property(String propertyName) throws MissingPropertyException {
        return super.property(propertyName);
    }

    public boolean hasProperty(String propertyName) {
        return super.hasProperty(propertyName);
    }

    public void setProperty(String name, Object value) {
        super.setProperty(name, value);
    }

I think “property” in the example was more a placeholder for any property name.
And besides that, you should never add such convenience setter and getter methods nowadays anyway.
Just expose the property and that’s it like:

public abstract class MyTask extends DefaultTask {
    @Input
    public abstract Property<String> getProperty();

    @TaskAction
    public void doStuff() {
        String propertyValue = property.get();
        // do stuff with propertyValue 
    }
}

(of course “property” is still a placeholder for a better name)

I totally agree with that, and I just wanted to say the same, just as others already pointed out:

The best way to create a property is I think to use an abstract class, just as you described:

Those “others” are also me :smiley:

1 Like