small refactr logo
At refactr we believe in the value of connection, the utility of agile processes, and the power of great ideas. We are creating the next generation of software for people who expect more from their web applications.
refactr
« Refactr Intrview Series: Marc Palmer | Congratulations to Graeme & Guillaume »


Groovy Builders


I’ve still been thinking about Builders so I dug into Groovy Builders and presented at the Groovy Users of Minnesota (GUM) meeting last night. Since I was inspired by Nat’s post, I used the same example domain that he used.

Builders encapsulate the logic of how an object is assembled. Groovy Builders do this using a tree based syntax. Starting with the end in mind - and after doing a little research into how Groovy Builders work (Chapter 8 of Groovy in Action is a great start) - as a basic first step, this is how I would like to describe an invoice:

def invoice = builder.invoice()
{
  recipient(name:'Sherlock Holmes')
  {
    address(street:'222b Baker Street', city:'London')
  }
  invoiceLines
  {
    invoiceLine(item:'Deerstalker Hat')
    {
      poundsShillingsPence(pounds:0, shillings:3, pence:10)
    }
    invoiceLine(item:'Tweed Cape')
    {
      poundsShillingsPence(pounds:0, shillings:4, pence:12)
    }
  }
}

Now for a quick intro into how Groovy Builders work. Creating a builder begins by extending the abstract class BuilderSupport and implementing a few createNode() methods and a setParent() method (with an option to implement nodeCompleted()). The following pseudocode illustrates how BuilderSupport uses these callback methods:

invoice = createNode('invoice')
//setParent() is not called on the root node
 
  recipient = createNode('recipient', [name:'Sherlock Holmes'])
  setParent(invoice, recipient)
 
    address = createNode('address', [street:'222b Baker', city:'London'])
    setParent(recipient, address)
    nodeCompleted(recipient, address)
 
  nodeCompleted(invoice, recipient)
  // etc ...
nodeCompleted(null, invoice)

I started down the path of creating an InvoiceBuilder as Nat had, but then I started thinking that I could do it in a more generic way that may fit what I needed to do. So rather than start in that direction, for the purposes of this example I decided to create a generic ObjectGraphBuilder that would build any object tree for me, as long as I followed some naming conventions along the way. Here’s the important bits of my builder:

class ObjectGraphBuilder extends BuilderSupport {
  def createNode(def name, Map attributes, def value) {
    if(attributes) {
      return Class.forName(capitalize(name)).newInstance(attributes)
    } else {
      return Class.forName(capitalize(name)).newInstance()
    }
  }
  def setParent(def parent, def child) {
    setObject(child, parent)
    setObject(parent, child)
  }
}

The capitalize() and setObject() methods are just helper methods I created that don’t really have any bearing on how the builder works. The first just uses WordUtils to capitalize the node name and the builder makes the assumption that it should instantiate a class by that name. The second uses reflection to fill in the association between the parent and child nodes as appropriate. The interested reader can find the code available here at the GUM Google Code repository. In addition to the builder and domain classes, there’s a test that executes the builder and asserts that the structure is set up as expected.

For building data objects for test purposes, this example doesn’t quite get to the level of simplicity that Nat’s example does. But next up, I’m hoping to work up an example using nested builders, which may do a better job for that purpose.

This entry was posted by Scott Vlaminck on Wednesday, October 10th, 2007 at 10:22 am and is filed under Agile Processes. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Further Discussion (5 Responses so far. Add yours)

  1. Enfranchised Mind » links for 2007-10-11 said...
    […] refactr Blog Archive ยป Groovy Builders Nice description of builders from the Refactr people. (tags: groovy programming) […]

  2. Andres Almiray said...
    ObjectGraphBuilder is a great idea, have you considered the possibility of donating it to the Groovy project? =)

  3. Scott Vlaminck said...
    I have definitely thought about contributing the code to the Groovy project. The ObjectGraphBuilder I have is currently pretty naive, so I was planning to put more time into it first. But I guess I should probably just contribute it and worry about improving it later. That way it would be of more use to others sooner.

  4. refactr Blog Archive » Refactr Contributions to Grails and Groovy said...
    […] still been working with Groovy Builders in my free time lately. With quite a bit of help from Andres Almiray to refactor my […]

  5. Mike Henderson said...
    Hi,

    I tried something similar a while back: http://www.behindthesite.com/blog/C663408438/E876434710/index.html

    I never got to use it for real and I’m not sure if the builder API has changed.

    Cheers,

    Mike

Join the Discussion