I have this code:
String buildCatalog(Catalog catalog) {
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.catalog(xmlns:'http://www.sybrium.com/XMLSchema/NodeCatalog') {
'identity'() {
groupId(catalog.groupId)
artifactId(catalog.artifactId)
version(catalog.version)
}
}
return writer.toString();
}
It produces this xml:
<catalog xmlns='http://www.sybrium.com/XMLSchema/NodeCatalog'>
<groupId>sample.group</groupId>
<artifactId>sample-artifact</artifactId>
<version>1.0.0</version>
</catalog>
Notice that the "identity" tag is missing... I've tried everything in the world to get that node to appear. I'm ripping my hair out!
Thanks in advance.
There might be a better way, but one trick is to call
invokeMethod
directly:This is effectively what Groovy is doing behind the scenes. I couldn't get
delegate.identity
orowner.identity
to work, which are the usual tricks.Edit: I figured out what's going on.
Groovy adds a method with a signature of
identity(Closure c)
to every object.This means that when you tried to dynamically invoke the
identity
element on the XML builder, while passing in a single closure argument, it was calling theidentity()
method, which is like callingdelegate({...})
on the outer closure.Using the
invokeMethod
trick forces Groovy to bypass the Meta Object Protocol and treat the method as a dynamic method, even though theidentity
method already exists on the MetaObject.Knowing this, we can put together a better, more legible solution. All we have to do is change the signature of the method, like so:
This is much more readable, it's clearer the intent, and the comment should (hopefully) prevent anyone from removing the "unnecessary" empty map.