Easier builders in Java
Anyone that has used the builder pattern for building simple Pojo-style Java classes is probably aware that writing these builder classes quickly becomes quite unpleasant and definitely not fun. You quickly realize that your builders often mimic the structure of your Pojo’s setters, finding yourself almost duplicating half of Pojo’s code for the sake of the pattern.
Following a recent post from Eric Mignot and a few prior reflections I had on optimizing the process of writing these builders, I have come up with a solution that will, I hope, greatly simplify trivial cases (that is, building simple pojos) and, eventually, as the tool evolves, allow for slightly more complex cases to be covered.
So, let me introduce you to the Fluent Interface Proxy Builder. The tool only requires the developer to write the builder interface, not the implementation. The actual implementation is assured by a dynamic proxy that will intercept method calls on your interface, then set the corresponding properties on your Pojo object.
Quick example. Suppose you have a simple Java Pojo:
public class Person {
private String name;
private int age;
private Person partner;
private List<Person> friends;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setPartner(Person partner) {
this.partner = partner;
}
public void setFriends(List<Person> friends) {
this.friends = friends;
}
// ... getters omitted for brevity ...
}
To get a builder for this bean, write a builder interface following a few naming conventions:
public interface PersonBuilder extends Builder<Person> {
PersonBuilder withName(String name);
PersonBuilder withAge(int age);
PersonBuilder withPartner(PersonBuilder partner);
PersonBuilder havingFriends(PersonBuilder... friends);
Person build();
}
Note: The parent interface “Builder” used here is provided by the framework. This interface has a “T build()” method. I included the “build” method in the example above for the sake of clarity. You may also use your own super interface if using the one provided by the framework proves to be a problem.
To use your builder, first create an instance:
PersonBuilder builder = ReflectionBuilder
.implementationFor(PersonBuilder.class)
.create();
Then you may use this dynamic builder normally through your interface:
Person person = aPerson()
.withName("John Doe")
.withAge(44)
.withPartner( aPerson().withName("Diane Doe") )
.havingFriends(
aPerson().withName("Smitty Smith"),
aPerson().withName("Joe Anderson"))
.build();
Have a look at the Github project page for all the details and instructions on how to use it in your own project. You may use this freely by the terms of the MIT license.
It is also worth mentioning other alternatives that exist and deserve consideration:
- a small framework named make-it-easy with which you describe how your beans are built and then it lets you call the builder code using a custom DSL. Similar in mindset to what Hamcrest Matchers provide for unit test assertions.
- generating builder code from annotations on your Pojo
- or generating builder code directly from your preferred IDE.
The slight annoyance I see with the latter two (code-generating approaches) is that since the code is generated, it will overwrite any naming customization you’d make after the initial generation. It also makes maintenance of the builder harder over time, as the objects being built evolve. From my point of view, adding a method on an interface is quicker and more natural than re-generating the builders (and possibly overwriting custom names).