Extending NamedDomainObjectContainers

Hi to all,

I want to define the following dsl syntax:

hosts {

host1 {

foo {

}

}

host2 { …

} }

where the hosts are added as container extension:

def hosts = project.container(Host)

I want to extend this Host objects in a second plugin.

In this plugin I tried the following:

for (Host nextHost: project.hosts)

nextHost.extensions.create(‘foo’, Foo, nextHost)

while Host implements ExtensionAware interface and holds a

private ExtensionContainer extensionContainer = new DefaultConvention() which is returned in getExtensions()

My problem is, that the container of hosts is empty when I want to register the foo extension.

Putting this registration into an afterEvaluate() brings an error.

Can you give me advice how to solve this?

Thank you Markus

Hi Markus,

couldn’t you do something like this:

<code>
project.hosts.all{ nextHost ->
     nextHost.extensions.create(‘foo’, Foo, nextHost) 
}
</code>

.all is a hook that is called for every item already in the container and everytime a new item is added.

cheers,
rene

Hi Rene, thank you for you answer,

I changed this like you told me. I think it now goes one step ahead, but doesn’t work completely

I create extensionContainer like

extensionContainer = new DefaultConvention(project.services.get(Instantiator)),

in a lazy getter getExtensions() in the Host class, because with default constructor of DefaultConvention I got an exception.

But now I have the following behavior:

As long as I do not define a dsl, which uses the foo,

e.g.

hosts {

testproject {

} }

everything works fine,

but as soon as I use this extended dsl, like hosts {

testhost {

foo { …

}

} }

I get an error Caused by: org.gradle.api.internal.MissingMethodException: Could not find method testhost() for arguments [pike_60hl1miv3hqfhsqsgf8g1l5der$_run_closure3_closure6@108f6716] on root project ‘testprojectVagrant’.

at org.gradle.api.internal.AbstractDynamicObject.methodMissingException(AbstractDynamicObject.java:68)

at org.gradle.api.internal.AbstractDynamicObject.invokeMetho…

I don’t understand what is going on in this case Can you please give me a hint?

Thanks

Markus

Hey Markus, it is a bit trickier than I thought, as the objects in a namedobject container are not automatically extensionaware (which is private gradle API at the moment).

I created a simple working example (without capsuling stuff in plugins but in a plain build.gradle file) for your usecase (using some private api (not avoidable atm if you really need that) at https://gist.github.com/breskeby/519cee19d3cb6127fff6

hope that helps. if you have more questions about that, just ask

Hi Rene,

I even don’t dare to tell you what was my fault…

I have multiple container extensions ,but tried to configure the foo extension at a container, where I didn’t register this extension :slight_smile:

But looking at your example, I became acquainted to the notion of NamedDomainObjectFactory.

thank you for your investigation and the example you have added to github.

This works like a charm.

Cheers Markus

I updated the gist to me way simpler. the instantiator takes care of the interface foo for you and your Host class can be dead simple