Lazy Extension Properties


I am trying to understand the correct way to create an extension that has nested types and Provider Api properties that is totally lazy.

Should nested types be wrapped in a property? If so how do we get the dsl syntax? Should kotlin receiver types be used or should just the gradle api Action interface?

// extension
open class Example @Inject constructor(objectFactory: ObjectFactory) {
  val nested: Property<Nested> =

  // Is this okay to configure the property?
  fun nested(configure: Nested) {
  // or should i use the action type?
  fun data(configure: Action<Nested>) {
        val configured = nested.get().apply {

// nested
open class Nested {
  var value = "bar"

example {
  // How do we do this?
  nested {
    value = "val"

Should nested types also have provider based members too or should the nested type just be a poko/pojo?

open class Nested {
  var value = "bar"

// vs

open class Nested @Inject constructor(objectFactory: ObjectFactory) {
  val value: Property<String> =

And my final question is around ObjectFactory.newInstance. Is the object that is created soley decorated by gradle to be extensible or is it lazy as well?


  • Edits
    I have looked at the plugin guide and the section on nested (custom data) doesn’t use the provider api.

Also the plugin guide has custom setters when the Lazy Configuration Guide specifically says to avoid this. Otherwise I might just expose different member that sets the provider type.

1 Like

For those interested later:

I ended up with properties on each model as the provider api documents.

Then for the DSL nesting I learned that when gradle creates an extension it makes it extension aware which means the extension itself can be extended which allows for the DSL like api.

       val root = project.extensions.create(

        val awareRoot = root as? ExtensionAware
        awareRoot?.extensions?.run {
        } ?: throw GradleException("Gradle didn't make aware root")

I never ended up using the newInstance method. All of the properties are initialized inline

val myProp: Property<String> {
        set("default value")