# Plugin extension with lazy properties

**URL:** <https://discuss.gradle.org/t/plugin-extension-with-lazy-properties/41368>\
**Category:** Help/Discuss\
**Created:** [November 5, 2021, 7:58am UTC](https://discuss.gradle.org/t/plugin-extension-with-lazy-properties/41368 "2021-11-05T07:58:48Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![radudh](https://avatars.discourse-cdn.com/v4/letter/r/898d66/32.png) [@radudh](https://discuss.gradle.org/u/radudh)\
**Post date:** [November 5, 2021, 7:58am UTC](https://discuss.gradle.org/t/plugin-extension-with-lazy-properties/41368/1 "2021-11-05T07:58:48Z")

</div>

I try to build a plugin using the latest guidelines, with lazy properties.

In the current form, the script crashes on evaluation, with message:

`Cannot set the value of read-only property 'logFolder' for object of type Target$Inject.`

If I comment the line `abstract Property<String> getLogFolder()` and uncomment the next one, it works.  
But now `logFolder` is no longer a lazy property.

What is the best way of creating such an extension?

Gradle version is 6.9.1, java is 8, language is Groovy.  
The simplified code is below:

```gradle
apply plugin: MyPlugin

abstract class Target {
    String name

    abstract Property<String> getLogFolder()
    // String logFolder

    Target(String name) {
        this.name = name
    }
}

abstract class MyExtension {
    abstract Property<String> getExtra()
    abstract NamedDomainObjectContainer<Target> targets

    MyExtension(NamedDomainObjectContainer<Target> targets) {
        this.targets = targets
    }

    def targets(Closure closure) {
        targets.configure(closure)
    }
}

class MyPlugin implements Plugin<Project> {

    void apply(Project project) {
        NamedDomainObjectContainer<Target> targetsContainer = project.container(Target)
        project.extensions.create("myx", MyExtension, targetsContainer)
    }
}

// test config
myx {
    extra = 'extra prop'

    targets {
        dev {
            logFolder = 'dev_folder'
        }

        prod {
            logFolder = 'prod_folder'
        }
    }
}

task show {
    doLast {
        println "extra is ${myx.extra.get()}; there are ${myx.targets.size()} targets"
        myx.targets.each { target ->
            println " ${target.name} - ${target.logFolder}"
        }
    }
}

```

---

<div class="post-metadata">

**Author:** ![Chris\_Dore](https://sea1.discourse-cdn.com/gradle/user_avatar/discuss.gradle.org/chris_dore/32/7592_2.png) [@Chris\_Dore](https://discuss.gradle.org/u/Chris_Dore)\
**Post date:** [November 7, 2021, 7:23am UTC](https://discuss.gradle.org/t/plugin-extension-with-lazy-properties/41368/2 "2021-11-07T07:23:34Z")

</div>

> For each container property, Gradle automatically adds a block to the Groovy and Kotlin DSL that you can use to configure the contents of the container  
> [Developing Custom Gradle Types](https://docs.gradle.org/6.9.1/userguide/custom_gradle_types.html)

So if your extension has a getter that returns a container type Gradle will generate the appropriate dsl code.

```gradle
abstract class MyExtension {
    abstract Property<String> getExtra()
    abstract NamedDomainObjectContainer<Target> getTargets()
}
class MyPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.extensions.create("myx", MyExtension)
    }
}

```

---

<div class="post-metadata">

**Author:** ![radudh](https://avatars.discourse-cdn.com/v4/letter/r/898d66/32.png) [@radudh](https://discuss.gradle.org/u/radudh)\
**Post date:** [November 7, 2021, 10:14am UTC](https://discuss.gradle.org/t/plugin-extension-with-lazy-properties/41368/3 "2021-11-07T10:14:12Z")

</div>

It works, thank you!

If someone else needs it, the working script is here:

```gradle
apply plugin: MyPlugin

abstract class Target {
    String name
    abstract Property<String> getLogFolder()

    Target(String name) {
        this.name = name
    }
}

abstract class MyExtension {
    abstract Property<String> getExtra()
    abstract NamedDomainObjectContainer<Target> getTargets()
}

class MyPlugin implements Plugin<Project> {

    void apply(Project project) {
        project.extensions.create("myx", MyExtension)
    }
}

// test config
myx {
    extra = 'extra prop'

    targets {
        dev {
            logFolder = 'dev_folder'
        }

        prod {
            logFolder = 'prod_folder'
        }
    }
}

task show {
    doLast {
        println "extra is ${myx.extra.get()}; there are ${myx.targets.size()} targets:"
        myx.targets.each { target ->
            println " ${target.name} - ${target.logFolder.get()}"
        }
    }
}

```
