Added Pros and Cons of Groovy MarkupBuilder
Two additional benefits of using the Groovy MarkupBuilder may not be immediately apparent. The first is that it is almost impossible to produce invalid markup because the builder opens and closes the nodes for you. As long as your code compiles, you will have well formed XML. The second benefit is that MarkupBuilder handles XML encoding of special characters (e.g., <, &, >, etc.), which are a constant source of trouble in normal template-based development. This reduces your vulnerability to cross-site scripting attacks without you having to even think about it.
However, if you use the Groovy MarkupBuilder to render your HTML, you will eventually find that it does not allow text elements to intermingle with structured elements as children. Currently, you could not produce the following, although it is legal and very common in XHTML:
<div id="main">
<p>Some <span class="special">highlighted</span> text</p>
</div>
You would need to output this using the MarkupBuilder as follows:
<div id="main">
<p>
<span>Some</span>
<span class="special">highlighted</span>
<span>text</span>
</p>
</div>
This is not ideal, but it is possible to create a specific HTML builder to solve the current issues with the Groovy MarkupBuilder while keeping all the existing benefits (which is beyond the scope of this article).
Performance Penalty
One negative aspect of Groovy builders is their slow performance, caused by their heavy dependency on Groovy meta-programming. Groovy builders redirect a lot of method calls behind the scenes to provide the nested closure syntax. In fairly small pages, this isn't cause for much concern. However, web pages that contain a large number of markup tags and require fast response times over the Internet tend to be slow if they are produced with a Groovy builder.
To gauge the difference between Java and Groovy performance for rendering HTML, the downloadable code provides a test called PerformanceTest.whichIsFaster. Run this test to see how the performances compare on your machine. The test generates an HTML table of results with 300 rows. Table 1 presents some results from my development machine.
Table 1. PerformanceTest.whichIsFaster Results from Author's Machine |
Run Number |
Java HTML Builder Using Proxy |
MarkupBuilder Without Caching |
GroovyMarkup Builder with Caching |
Run 1 |
84 ms |
753 ms |
201 ms |
Run 2 |
51 ms |
539 ms |
199 ms |
Run 3 |
51 ms |
535 ms |
199 ms |
Run 4 |
51 ms |
533 ms |
195 ms |
Run 5 |
52 ms |
529 ms |
199 ms |
The MarkupBuilder has two results per run because Groovy has such a high startup cost for the first execution. Subsequent executions are much faster, but still nowhere near as fast as Java's.
The Internal DSL Approach
Groovy builders bring a level of expressiveness within code that previously was unavailable for the Java platform. This gives you the freedom to move away from the external DSL approach of template engines to the simpler, more powerful and testable internal DSL approach. There are performance problems when rendering large pages, but in these instances you can drop into Java to reduce response times.
As a final thought for improving the usage of builders, it would be great to be able to define the usage of a builder, either through a schema or programmatic constraints. This was discussed recently on the Groovy DZone, StateMachine: A Builder-Builder for Groovy, Part 1.