A few days ago I was discussing the topic of builders during a Grails training session. After surveying the usual suspects found in the standard Groovy distribution (MarkupBuilder, SwingBuilder, Antbuilder and ObjectGraphBuilder) we jumped into Grails' DomainBuilder. Once we got familiar with it the team seized the opportunity to refactor an existing application they've been working on for a few weeks. The idea was to remove a very verbose data setup during the bootstrap sequence.
Like many other applications out there, this one requires setting up users and roles to secure access to some areas. The User and Role classes looked like the following ones
Nothing complex really. Now, during bootstrap there were a handful on instances of both classes being created and saved. A few users would share roles which meant keeping a reference to the common role to later use Grails relationship methods. This caused the code to be not so much DRY, and while it's good to be WET from time to time this wasn't the case. Let me show you how the code looked like before we added the builder
We could have saved a few lines by collecting all domain classes in Lists then applying *.save() on the lists, however that would still have left the relationship methods being defined explicitly. This is where DomainBuilder came in. With it we were able to define the domain instances and the relationships at the same time. We ended up with code looking like the following one
DomainBuilder understands perfectly well the relationships between domain class instances. It also makes some assumptions on how the model is setup, but we still need to give it a few hints. In line 7 we can see a classNameResolver set on the builder. By convention the builder will use an strategy to construct fully qualified classnames out of node names. If the classes happen to be defined inside a package then you must define a custom classNameResolver. In our case the classes we're interested in live under the same package so we only need to specify it, the builder will do the rest to figure out the correct class name.
Next, we must set a custom identifierResolver because the id property is of semantic meaning to domain classes. The builder can keep references to all instantiated nodes, it will use the id property by default, assuming that's a synthetic property. This means it will treated in a different way than the rest of properties. Because id is used by domain classes we set a different synthetic property named nodeId. Finally we define a custom factory to serve as the root of the object graph. This custom factory requires additional setup to handle its children, which is why we also register a custom ChildPropertySetter on the builder. These two helper classes can be seen in the following snippets
Basically the code inspects the type of the parent node. If it's a List then we append the child to it, otherwise we let the standard behavior take control. You can read more information on the builders used at FactoryBuilderSupport and ObjectGraphBuilder.
Keep on Groovying!