In one of my projects we had very complicated domain model, which included more than hundred of different domain object types. It was a pure Java project and, honestly, Java is very verbose with respect to object instantiation, initialization and setting properties. Suddenly, the new requirement to allow users define and use own object models came up. So ... the journey begun.
We ended up with the idea that some kind of domain language for describing all those object types and relations is required. Here Groovy came on rescue. In this post I would like to demonstrate how powerful and expressive could be simple DSL written using Groovy builders.
As always, let's start with POM file for our sample project:
I will use the latest Groovy version, 1.8.4. Our domain model will include three classes: Organization, User and Group. Each Organization has a mandatory name, some users and some groups. Each group can have some users as members. Pretty simple, so here are our Java classes.4.0.0 com.example dsl 0.0.1-SNAPSHOT jar UTF-8 junit junit 4.10 org.codehaus.groovy groovy-all 1.8.4 org.codehaus.gmaven gmaven-plugin 1.4 1.8 compile testCompile org.apache.maven.plugins maven-compiler-plugin 2.3.1 1.6
Organization.java
package com.example; import java.util.Collection; public class Organization { private String name; private Collection< User > users = new ArrayList< User >(); private Collection< Group > groups = new ArrayList< Group >(); public String getName() { return name; } public void setName( final String name ) { this.name = name; } public Collection< Group > getGroups() { return groups; } public void setGroups( final Collection< Group > groups ) { this.groups = groups; } public Collection< User > getUsers() { return users; } public void setUsers( final Collection< User > users ) { this.users = users; } }
User.java
package com.example; public class User { private String name; public String getName() { return name; } public void setName( final String name ) { this.name = name; } }
Group .java
package com.example; import java.util.Collection; public class Group { private String name; private Collection< User > users = new ArrayList< User >(); public void setName( final String name ) { this.name = name; } public String getName() { return name; } public Collection< User > getUsers() { return users; } public void setUsers( final Collection< User > users ) { this.users = users; } }Now, we have our domain model. Let think about the way regular user can describe own organization with users, groups and relations between all these objects. Primarily, we taking about some kind of human readable language simple enough for regular user to understand. Meet Groovy builders.
package com.example.dsl.samples class SampleOrganization { def build() { def builder = new ObjectGraphBuilder( classLoader: SampleOrganization.class.classLoader, classNameResolver: "com.example" ) return builder.organization( name: "Sample Organization" ) { users = [ user( id: "john", name: "John" ), user( id: "samanta", name: "Samanta" ), user( id: "tom", name: "Tom" ) ] groups = [ group( id: "administrators", name: "administrators", users: [ john, tom ] ), group( id: "managers", name: "managers", users: [ samanta ] ) ] } } }And here is small test case which verifies that our domain model is as expected:
package com.example.dsl import static org.junit.Assert.assertEquals import static org.junit.Assert.assertNotNull import org.junit.Test import com.example.dsl.samples.SampleOrganization class BuilderTestCase { @Test void 'build organization and verify users, groups' () { def organization = new SampleOrganization().build() assertEquals 3, organization.users.size() assertEquals 2, organization.groups.size() assertEquals "Sample Organization", organization.name } }I am using this simple DSL again and again across many projects. It's really simplifies a lot complex object models creation.