MetaBuilder

What is it?

MetaBuilder is a builder that builds builders.

If you aren't already familiar with the concept of builders, or with builders in Groovy, start with Groovy's online Builder description or even better, see the top-rated Groovy book, Groovy in Action, Chapter 8, Working with Builders.

If you are already familiar with the concept of builders, then a quick example is probably the best way to give you a feel for what MetaBuilder can do.

A Quick Example

To give you a quick idea of what can be done with MetaBuilder take a look at the following Groovy script and see if you can find the typo:

        def nb = new NodeBuilder()

        def anInvoice = nb.invoice(date: new Date()) {
            items {
                item(upc: 123, qty: 1, price: 14.99)
                item(upe: 234, qty: 4, price: 14.99)
                item(upc: 345, qty: 6, price: 14.99)
            }
        }

The typo in the second item would normally go undetected until possibly much later when something tries to process these nodes. MetaBuilder can catch this kind of error and do much more. But first you have to define a schema:

        import groovytools.builder.*

        def mb = new MetaBuilder()
        def invoiceSchema =  mb.define {
            invoice {
                properties {
                    date()
                }
                collections {
                    items {
                        item {
                            properties {
                                upc()
                                price()
                                qty()
                            }
                        }
                    }
                }
            }
        } 

MetaBuilder schema is easy to understand. Properties of an object are defined within a node called properties. Collections and maps are defined within a node called collections.

Ok, now that you have a schema, you use it almost exactly as before. I've highlighted the differences:

        def anInvoice = mb.build {
            invoice(date: new Date()) {
                items {
                    item(upc: 123, qty: 1, price: 14.99)
                    item(upe: 234, qty: 4, price: 14.99)
                    item(upc: 345, qty: 6, price: 14.99)
                }
            }
        } 

Of course, I left the typo in there so that we could see what MetaBuilder reports:

    groovytools.builder.PropertyException: Property 'upe': property unkown 

Now you get immediate feedback when there are errors in the build script.

MetaBuilder doesn't just create trees of Nodes, however. In fact, it's very easy to tell MetaBuilder to construct a very specific graph of objects by specifying the classes to use in the schema. For the next example, assume you have the following classes:

    class Invoice {
        def date
        def items = []
    }

    class Item {
        def upc
        def qty
        def price
    } 

Here is what you would do to the previous schema to have MetaBuilder now construct an Invoice as above:

        import groovytools.builder.*

        def mb = new MetaBuilder()
        def invoiceSchema =  mb.define {
            invoice (factory: Invoice) {
                properties {
                    date()
                }
                collections {
                    items {
                        item (factory: Item) {
                            properties {
                                upc()
                                price()
                                qty()
                            }
                        }
                    }
                }
            }
        } 

Now, without any other changes, executing the build script just as before but with the new schema returns an Invoice!

        def anInvoice = mb.build {
            invoice(date: new Date()) {
                items {
                    item(upc: 123, qty: 1, price: 14.99)
                    item(upe: 234, qty: 4, price: 14.99)
                    item(upc: 345, qty: 6, price: 14.99)
                }
            }
        }
        assert(anInvoice instanceof Invoice)

Documentation and Examples

Download and Installation

Getting Help

Licensing

SourceForge Logo