Implementing the builder pattern with Jackson

The builder pattern allows for the construction of an object step by step (properties by properties). This comes handy while writing tests as this is when we want to instantiate the object being tested precisely in the state deemed useful for the test.

When the object under test is a “Thing”, with 2 properties name and description:

class Thing
{
    private String name;

    private String description;

    public String toString(){
        return String.format("name:%s description:%s", name, description);
    }

   public Thing(){}

   public Thing(String name, String description){
        this.name = name;
        this.description = description;
    }

    String getName() {
        return name;
    }

    void setName(String name) {
        this.name = name;
    }

    String getDescription() {
        return description;
    }

    void setDescription(String description) {
        this.description = description;
    }
}

Then the first approach to constructing a builder for the Thing is to expose a list of “with-er” methods (chained setters under another name) eg. “withName(…)”, “withDescription(…)” and so on, where each method maps to a property of the Thing.

public class Builder {

    private String name;
    private String description;

    public Thing build(){
        return new Thing(name, description);
    }

    public Builder withName(String name){
        this.name = name;
        return this;
    }

    public Builder withDescription(String description){
        this.description = description;
        return this;
    }
}

and the associated test:

public class BuilderTest{

    @Test
    public void testBuilder(){
        Thing aThing = new Builder()
            .withName("aname")
            .withDescription("somedesc")
            .build();

        assertThat(aThing.getDescription(),is("desc"));
        assertThat(aThing.getName(), is("aname"));
    }
}

Second approach: use the Jackson processor to directly instantiate a Thing from a json string.

public class JsonBuilder {

    private Thing thing =null;

    public Thing build(){
        return thing;
    }

    public JsonBuilder add(String s) throws  IOException {
        this.thing = new ObjectMapper().readValue(convertToJson(s), Thing.class);
        return this;
    }

    private String convertToJson(String nvps){
        String json = nvps.replaceAll("([A-za-z0-9.]+)","\"$1\"");
        json = "{" + json + "}";
        return json;
    }
}

and the test:


public class JsonBuilderTest {

    private final JsonBuilder builder = new JsonBuilder();
   
    @Test
    public void testJsonBuilder() throws Exception{
        Thing aThing = builder.add("name:aname,description:desc").build();
        
        assertThat(aThing.getDescription(),is("somedesc"));
        assertThat(aThing.getName(),is("aname"));
    }
}

See how with Jackson the code required to instantiate the object under test is less verbose and more compact than the alternative approach. The downside is a slightly more fragile code (more prone to typos) since the json string cannot be checked at compile time.

Full source code for the samples above is here.

Advertisements

One thought on “Implementing the builder pattern with Jackson

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s