As if there weren't enough options already for constructing your own
builders in Groovy, along comes another: MetaBuilder. Quite literally,
MetaBuilder is a builder that builds builders. Through some simple
examples, this article will show you how you can put MetaBuilder
to work for you in just three easy steps. To follow along, simply visit
SourceForge to get the MetaBuilder distribution and include
groovytools-builder-x.x.x.jar in your classpath.
Oh, and you'll also need Groovy 1.5 and Java 1.5, too
MetaBuilder in Three Easy Steps
- Create an instance of MetaBuilder
- Define your domain specific language (DSL)
- Build your objects
Create an instance of MetaBuilder
There's almost nothing to this step but just to call a constructor:
Define Your Domain Specific Langauge (DSL)
MetaBuilder provides a DSL, implemented as a Groovy builder, for defining
your own builders. If you are already familiar with builders in Groovy,
it takes just one simple example to get you started. Continuing where
we left off above, let's start defining a customer class and customer
In the previous snippet,
define is used to tell MetaBuilder that we
are going to create some new definitions, or schema, for the objects that
our new builder can create. MetaBuilder keeps track of our definitions
and it's even possible to reuse and extend these definitions, as we'll
customer is the name of the schema and the
tells MetaBuilder what object to create whenever a customer is to be
properties contains a list of property names.
Build Your Objects
Building objects is now just a matter of telling MetaBuilder that is
what you want to do:
Great! If you've been following along in your own IDE, you hopefully
now have the basics down and are ready to take a look at some advanced
What would happen if you used a property that was not in the schema or
mistyped a legitimate property name? For example:
If you executed this, MetaBuilder will throw the following exception:
groovytools.builder.PropertyException: Property 'dob': property unkown
Assuming you fix
dob only and retry, MetaBuilder will throw another exception:
groovytools.builder.PropertyException: Property 'phone': property unkown
Despite the fact that
phone is a property of your class, MetaBuilder only goes by what's in your
schema. That kind of checking is nice to have and MetaBuilder can do even more with some additional information.
Controlling the Build
The purpose of this section is to go a bit deeper into MetaBuilder's capabilities.
Let's take another look at the
factory attribute used earlier. By
simply specifying the
factory attribute in your schemas, you tell
MetaBuilder how to build the right object every time. MetaBuilder was
designed to accept as wide a variety of values as possible. For example,
you can specify the
factory attribute as any of the following:
- Class, i.e.
- String, i.e.
- instance of
Feel free to consult MetaBuilder Meta-Schema for all the gory details on each of the attribute values MetaBuilder accepts.
This next example demonstrates how one might use closure to create
MetaBuilder supports a number of useful attributes on properties. These include the following:
def: the default value or a Closure to produce the default value, as needed
req: if true, a value must be specfied (it could be null though)
property: an alternative property name or Closure to use to set the value
min: the minimum length for a property value
max: the maximum length for a property value
check: causes an exception if the value fails the following test: Here's an example showing combinations of some of the above:
Reusing and Extending Schema: the
schema attribute to tell MetaBuilder that you want to reuse
a schema. In the next example, we'll create a new
Phone class and
update our schema to use it:
Now, let's make
phone a required property on our
So far, we've only looked at examples of properties, but MetaBuilder also
supports collections. You define collections like you define properties,
just provide a list of them and set attributes as needed.
The above definition extends Customer and adds a list of phone numbers
and a map of addresses. Like properties, collections are mapped to
properties of an object by the name.
address is defined directly within the collection.
Nesting definitions can make the definitiona bit more brief, but comes
at the risk of creating definitions that aren't as easily reused.
Another thing to note is the use of the
key attribute in the
addresses collection. Presenece of the
key attribute tells
MetaBuilder that the parent-child relationship is indexed. In the
following example, you can see that
customer5 has both a list of
phone and map of
addresses using the
and the key.
Collections support a number of useful properties:
collection: specifies an alternate name for the collection or a Closure used to get the collection from the parent.
key: specifies a property name or a Closure used to get the key from a child. Also indicates the collection is a map.
add: specifies a method name or Closure used to add the child directly to the parent, supercedes
min: the minimum size of the collection
max: the maximum size of the collection
size: alternate method or Closure that may be used to get the collection size.
Where to Go From Here
This whirlwind tour of MetaBuilder really only just scratched the surface
of its features and capabilities. If you get stuck, be sure to check out
the MetaBuilder Meta-Schema, which describes the entire MetaBuilder feature set.
Also included in the release are a number of tests and examples that are also useful to look at.