Trying to use lazy configuration properties on a Groovy Binary Plugin

Hello!

I’m in the process of writing some of my first Gradle binary plugins using Groovy as a basis (using the groovy-gradle-plugin to access the API).

I’m struggling to implement a plugin with an extension that provides lazy configuration properties. What I’m seeing is that when I provide a convention on the Property, that value is always being used, despite a build.gradle that consumes the plugin specifying a different value.

MyPlugin.groovy:

abstract class MyPluginExtension {
    abstract Property<Boolean> feature
    MyPluginExtension(ObjectFactory factory) {
        feature = factory.property(Boolean)
    }
}

class MyPlugin implements Plugin<Project> {

    @Override
    void apply(Project project) {
        def extension = project.extensions.create('myplugin', MyPluginExtension, project.objects)
        extension.feature.convention(false)
        if (extension.feature.get()) {
            println("Feature is enabled")
        } else {
            println("Feature is disabled")
        }
    }
}

build.gradle (Consumer):

plugins {
	id 'myplugin' version '1.0-SNAPSHOT'
}

myplugin {
	feature.set(true)
}

And the output when running shows this:

> Configure project :myproject
Feature is disabled

The Implementing Gradle Plugins page only describes implementing a binary plugin in Java - I’m unsure if that’s causing any of the issue I’m seeing: Implementing Gradle plugins.

I may also be combining ideas here, but the Lazy Configuration page shows it being implemented as an Interface instead: Lazy Configuration

I’ve found this Kotlin example which looks very similar to what I’d like to achieve: Gradle custom extension with lazy configuration doesn't work - #2 by Vampire

And if it’s not already obvious, I’d like to avoid project.afterEvaluate at all costs :slight_smile:

I’ve found the solution to this. The issue I was having was that I was trying to use the evaluation of get() too early. This isn’t seen in my example above. As @Vampire pointed out on the Slack channel, you should evaluate the property at the ‘latest’ point in the lifecycle. So if you want to have an extension property that disables the jar task, you should evaluate the extension property during the configure method closure of that task.

project.tasks.named('jar').configure {
    enabled = extension.jarTaskEnabled.get()
}

This isn’t seen in my example above

It is:
image
:slight_smile:

you should evaluate the property at the ‘latest’ point in the lifecycle

Exactly, and optimally this should be the execution phase.

So if you want to have an extension property that disables the jar task, you should evaluate the extension property during the configure method closure of that task.

Almost.
If you do it like that, you still have the problem that it might be evaluated too early.
If you for example have a tasks.all { } or a tasks.jar.get() or similar (can also be done by some plugin you apply) again your evaluation happens before the configuration.

Instead you should use onlyIf { ... } on the task, as that is evaluated in the execution phase right before the task would have been executed and in there check your property.

1 Like