简体   繁体   中英

Nested extensions in Gradle plugin

I'm trying to achieve the following configuration in my gradle plugin

music {
    artist {
        artistName = "artist1"
        album {
            albumName = "album1"
        }
    }
    artist {
        artistName = "artist2"
        album {
            albumName = "album1"
        }
        album {
            albumName = "album1"
        }
    }
}

And this is what I have so far

open class MusicPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        project.extensions.create("music", MusicPluginExtension::class.java)
    }
}

open class MusicPluginExtension @Inject constructor(val objectFactory: ObjectFactory) {
    val artists = objectFactory.domainObjectSet(Artist::class.java)

    fun artist(action: Action<in Artist>) {
        val artist = Artist(objectFactory)
        action.execute(artist)
        artists.add(artist)
    }
}

open class Artist @Inject constructor(objectFactory: ObjectFactory) {
    var artistName: String? = null
    val albums = objectFactory.domainObjectSet(Album::class.java)

    fun album(action: Action<in Album>) {
        val album = Album()
        action.execute(album)
        albums.add(album)
    }
}

open class Album() {
    var albumName: String? = null
}

When I apply the plugin to a project, I am able to create the closures but get a failure when I try to set properties for an Album (ex. setting the name of the album). This is the error I get:

FAILURE: Build failed with an exception.

* Where:
Build file '/Users/user/git/pluginTest/build.gradle' line: 19

* What went wrong:
A problem occurred evaluating root project 'pluginTest'.
> Could not set unknown property 'albumName' for object of type com.plugin.Artist.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

CONFIGURE FAILED in 84ms

Any assistance with this would be greatly appreciated.

Probably you can use Gradle's NamedDomainObjectContainer .

interface MusicPluginExtension {
    // https://docs.gradle.org/current/userguide/custom_gradle_types.html#nameddomainobjectcontainer
    NamedDomainObjectContainer<Artist> getArtists()

    interface Artist {
        String getName()
        NamedDomainObjectContainer<Album> getAlbums()
        interface Album {
            String getName()
        }
    }
}
music {
    artists {
        register("artist1") {
            albums {
                register("album1"){}
                register("album2"){}
            }
        }
        register("artist2") {
            // ...
        }
    }
}

It works for 1-level nested list, maybe it would work with the 2-level list as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM