Deeply-nested extensions with plugins


I’m building a plugin that requires a reasonably-deeply-nested set of properties, which I’m trying to achieve using the extension container mechanism. So I’ve got a handful of extension classes, and I add them to the plugin like so:

A a = project.extensions.create(‘a’, A) B b = project.a.extensions.create(‘b’, B) C c = b.extensions.create(‘c’, C) …

where class A contains a B, and class B contains a C, and so on. Creating these seems to work ok.

My questions are:

  1. Is this the appropriate way to do deep property hierarchies for plugins? I haven’t had much luck finding many exampls that try to nest more than one extension. and which aren’t using the older ‘conventions’.

  2. What is the lifecycle of these extensions? i.e. what is the relative ordering of each extension’s construction, and how/when does each child extension get set on its parent (am I expected to inject these myself, or does Gradle do it for me?)? At what point does the configuration block from the build file get applied to each extension, and in what order are the properties applied? (i.e. do child extensions get initialized before parent ones?)

Any pointers to good examples would also be great.


Hey, The extensions are created just in the momemt the code you mentioned above is executed (i guess it’s part of your Plugin#apply routine?). That means that the lifecycle of a / b & c are tight to lifecycle of your plugin. I’m not sure if this is the answer you’re looking for. Maybe elaborate a bit more with an example you have in mind.

cheers, René

One of the things I was trying to understand is how the various nested levels of configuration/closure from the build script get bound to the various extensions.

Assume I have a closure like this (using the extensions I’ve already described above):

a {
    someAThing 'aaa'
    b {
        someBThing 'bbb'
        c {
            someCThing 'ccc'

Given this, what exactly gets ‘set’ on extension “a”? Is it just the setter for someAThing? What about the “b” closure? Based on the extensions above, does Gradle recognise that it needs to bind the contents of the b closure into the b extension? If yes, does the b extension actually have any concrete relationship to the a extension? I ask this because I noticed that even though I create extension b from extension a, a does not get injected with the instance of b. I have to explicitly set the extensions on one another by hand to build the extension object graph (if I do not do this, and I call a.b.someBThing, I get a NPE).