Custom task closure property becomes null

build.gradle:

class MyTask extends DefaultTask {
    Closure<String> prop = { "123" }
}
  task myTask(type: MyTask) << {
    println prop
    println prop.call()
    println prop.call()
    println prop()
    println prop
}

output after running gradle myTask:

:myTask
MyTask$_closure1@33fc018e
123
123
null
null

after calling closure with prop() field prop becomes null. Using prop.call() behaves correctly.

Why is this happening and what is the correct way of having and calling Closure properties in gradle tasks?

What are you trying to achieve with this task?

I need dynamic properties. Some properties are set during task creation and other are dynamically calculated based on them. Additionally I want to be able to replace calculation logic with overriding task closure prop.

From my perspective the logic should be encapsulated in the custom task and should be hidden from the user of the task. What you rather might want to do is to have different custom task implementations if you need to have different logic. In the consuming build script (the one that creates the enhanced task) you only want to provide values for certain properties configures these tasks.

I understand. But in this particular situation I want to have Closure property in my task. Gradle tasks are supposed to be POGOs or any JVM class. So when written in Groovy I expected default Groovy closure semantics: running closure with unnamed () invocation should be exactly as running ‘call()’ method. Now I need to explicitly write call() invocations to make it working.

For each task property ‘foo’, Gradle adds a method ‘foo’ that delegates to ‘setFoo’. So ‘foo()’ is the same as ‘setFoo()’, and since it’s missing an argument, Groovy adds a ‘null’. If you want to prevent this from happening, you can add your own ‘foo’ method that delegates to ‘foo.call()’.

Now it’s clear. Thanks.