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?

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

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: