Always Use Parenthesis in Groovy Builders

I recently ran into an interesting Groovy feature when demonstrating the strengths of the MarkupBuilder. As you probably know, parenthesis in a Groovy method call are optional, unless it’s a no-args call. In that case the parenthesis are needed in order to distinguish the call from a property. However, leaving out parenthesis in a Builder is asking for trouble. Consider this:

def w = new StringWriter()
def builder = new groovy.xml.MarkupBuilder(w)
builder.persons() {
    person(attr:'value')
}
println w

Resulting XML is:

<persons>
  <person attr='value' />
</persons>

Let’s remove the seemingly redundant parenthesis on the call to ‘person’:

def w = new StringWriter()
def builder = new groovy.xml.MarkupBuilder(w)
builder.persons() {
    person attr:'value'
}
println w

Resulting XML is:

<persons>
  <person attr='value' />
</persons>

Identical. Good, all is well, you think. But it’s not. We add an empty closure to ‘person’, which really should not have any effect:

def w = new StringWriter()
def builder = new groovy.xml.MarkupBuilder(w)
builder.persons() {
    person attr:'value' {}
}
println w

Resulting XML is:

<persons>
  <value />
  <person attr='value' />
</persons>

What happened here? An element was inserted with the same name as my attribute value.

Now, let’s add something to the empty closure:

def w = new StringWriter()
def builder = new groovy.xml.MarkupBuilder(w)
builder.persons() {
    person attr:'value' {
        kid()
    }
}
println w

Resulting XML is:

<persons>
  <value>
    <kid />
  </value>
  <person attr='value' />
</persons>

Even more strange. The ‘kid’ element ended up inside the ‘value’ element.

If I add parenthesis to ‘person’, then everything works as expected:

def w = new StringWriter()
def builder = new groovy.xml.MarkupBuilder(w)
builder.persons() {
    person(attr:'value') {
        kid()
    }
}
println w

Resulting XML is:

<persons>
  <person attr='value'>
    <kid />
  </person>
</persons>

I don’t want to turn this feather into something it is not. When using Builders, use parenthesis, end of story. However, for those of us that can’t let something like this pass, here follows my analysis.

The Groovy Statements page says:

If a method takes parameters you can leave the closure outside of the parenthesis (provided that the closure parameter is the last parameter on the underlying method).

    def value = [1, 2, 3].inject(0) { count, item -> count + item }
    assert value == 6

The above code is equivalent to the following (but just neater)

    def value = [1, 2, 3].inject(0, { count, item -> count + item })
    assert value == 6

So what does that tell us? Well, if our closure is really the last parameter to the ‘person’ call, then we should be able to write this:

def w = new StringWriter()
def builder = new groovy.xml.MarkupBuilder(w)
builder.persons() {
    person (attr:'value', {
        kid()
    })
}
println w

Note the comma after ‘value’. Let’s run that code:

<persons>
  <person attr='value'>
    <kid />
  </person>
</persons>

OK, it looks fine. However, when we skipped the parenthesis, we implicitly also skipped that crucial comma. In effect, we wrote what’s equivalent to this:

def w = new StringWriter()
def builder = new groovy.xml.MarkupBuilder(w)
builder.persons() {
    person (attr:'value' {
        kid()
    })
}
println w

This is really interesting. It looks like the only parameter to ‘person’ now is a single map entry attr that maps to … what exactly? Running this will result in the now well-known:

<persons>
  <value>
    <kid />
  </value>
  <person attr='value' />
</persons>

Can you see it yet?

This whole discussion started with the claim that parenthesis are optional to method calls. And that’s exactly what ‘value’ is: a method call with a Closure as a parameter:

'value' { kid() }

It’s OK to quote method names, for example if they contain illegal characters like ‘-‘, but it’s of course also OK to quote a method name that doesn’t contain illegal characters.

So, let’s define a method ‘value’ that takes a Closure as parameter, in order to see if it gets called:

def value(Closure c) { println 'inside method value'; return 'returned value'}
def w = new StringWriter()
def builder = new groovy.xml.MarkupBuilder(w)
builder.persons() {
    person (attr:'value' {
        kid()
    })
}
println w

We get this:

inside method value
<persons>
  <person attr='returned value' />
</persons>

Pretty convincing, right?

This Post Has One Comment

  1. Hi,

    nice analysis of the “problem” and always using parenthesis will return the correct code.

    You could also have added the comma in the version without parenthesis to get a good result:

    def w = new StringWriter()
    def builder = new groovy.xml.MarkupBuilder(w)
    builder.persons() {
    person attr:’value’, {
    kid()
    }
    }
    println w

Leave a Reply

Close Menu