Type-safe Builder Pattern in Java

13 08 2008

In this post I deviate a bit from the topic of my recent posts about Meta-Programming with Scala. I will have more to say about the latter topic in upcoming posts however.

Recently I read this rather fascinating post about a Type-safe Builder Pattern in Scala. When Heinz Kabutz mentioned the builder pattern in his latest issues of the The Java Specialists’ Newsletter I decided to try to come up with a type safe version for Java.

What I finally came up with is not strictly a builder but something I rather call an initializer. The initializer contains the initial state required by the target object. The state is accumulated within the initializer. Only when the state is complete can it be passed to the targets object’s constructor. Java’s type system prevents passing a initializer with an incomplete state to the target class’s constructor.

public class Foo {
  private final int a;
  private final int b;

  public Foo(Initializer<TRUE, TRUE> initializer) {
    this(initializer.a, initializer.b);
  }

  private Foo(int a, int b) {
    super();
    this.a = a;
    this.b = b;
  }

  public String toString() {
    return "a = " + a + ", b = " + b;
  }

  public static class Initializer<HA, HB> {
    private int a;
    private int b;

    private Initializer() {
      super();
    }

    private Initializer(int a, int b) {
      super();
      this.a = a;
      this.b = b;
    }

    public static Initializer<FALSE, FALSE>create() {
      return new Initializer<FALSE, FALSE>();
    }

    public Initializer<TRUE, HB> setA(int a) {
      this.a = a;
      return new Initializer<TRUE, HB>(a, this.b);
    }

    public Initializer<HA, TRUE> setB(int b) {
      this.b = b;
      return new Initializer<HA, TRUE>(this.a, b);
    }

    static abstract class TRUE {}
    static abstract class FALSE {}
  }

}

The basic technique is the same as for the Type-safe Builder Pattern in Scala: the phantom types TRUE and FALSE are used to keep track of the state. Only a complete state will result in a Initialiter instance which subsequently can be passed to Foo‘s constructor.

Here is how this is used:

public class Main {
  public static void main(String[] args) {
    Initializer<?, ?> initializer = Initializer.create();

    // Foo.create(initializer);           // won't compile
    // Foo.create(initializer.setB(1));   // won't compile
    // Foo.create(initializer.setA(1));   // won't compile

    Foo foo = new Foo(initializer.setA(1).setB(2));
    System.out.println(foo);
  }
}
About these ads

Actions

Information

9 responses

14 08 2008
Ricky Clarkson

I wrote the same thing in Java, then decided that it didn’t readably scale up to 10 parameters or so, which is the case that Builder is actually a useful pattern for. X[FALSE, FALSE, FALSE, FALSE, FALSE..] is difficult to call readable.

I don’t have a better answer though.

16 08 2008
Daily del.icio.us for August 11th through August 15th — Vinny Carpenter's blog

[...] Type-safe Builder Pattern in Java « Michid’s Weblog – Recently I read this rather fascinating post about a Type-safe Builder Pattern in Scala. When Heinz Kabutz mentioned the builder pattern in his latest issues of the The Java Specialists’ Newsletter I decided to try to come up with a type safe version for Java. [...]

18 08 2008
Matt

Nice!

@Ricky, I guess even with as many as ten parameters it’s plausible to call the entire builder in one expression, in which case the Initializer’s type is never named in the calling code.

18 08 2008
Ricky Clarkson

Matt,

True, but you see it in the implementation and in the IDE’s prompting while you’re writing the use. And if you work under a coding standard that prefers naming subexpressions to writing long lines (even with wrapping) the lack of type inference in Java makes the pain return.

19 02 2009
Przemek

Hi! Actually, in Java you can use a much simpler approach to get type-safe Builder (although Rafael’s approach looks nice it’s not really required in such case). You just declare a Builder’s constructor, that takes all required parameters. Then you set all optionals via chained Builder method calls.

If there are more required params, overloaded Builder constructor may help. In most complex cases (10 or more req. params), you can put static factory methods to Builder.

So phantom types are cool, but in this case there is better (and more KISSy) solution IMHO.

14 06 2010
Ecko

nice…
thanks..

25 02 2011
Friday feb 25th 2011 standup | Daily Stand up

[...] #2008 type safe builder pattern in java [...]

11 03 2012
Jonatan Jönsson

I prefer to set mandatory parameters using new Builder types as return values for each mandatory parameter, such as this:

public final class SomeClass
{
final int mandatoryField;
final String mandatoryString;
final boolean optionalField;

/**
* Starting point for creating SomeClass instanes
*/
public static IntermediateSomeClassBuilder withMandatoryField(final int m)
{
return new IntermediateSomeClassBuilder(m);
}

SomeClass(final SomeClassBuilder builder)
{
mandatoryField = builder.mandatoryField;
mandatoryString = builder.mandatoryString;
optionalField = builder.optionalField;
}

public static final class SomeClassBuilder
{
final int mandatoryField;
final String mandatoryString;
boolean optionalField;

SomeClassBuilder(final int mandatoryField, final String mandatoryString)
{
this.mandatoryField = mandatoryField;
this.mandatoryString = mandatoryString;
}

public SomeClassBuilder withOptionalField(final boolean optional)
{
this.optionalField = optional;
return this;
}

public SomeClass build()
{
return new SomeClass(this);
}
}

public static final class IntermediateSomeClassBuilder
{
private final int mandatoryField;
private IntermediateSomeClassBuilder(final int mandatoryField)
{
this.mandatoryField = mandatoryField;
}

public SomeClassBuilder withMandatoryString(final String mandatoryString)
{
return new SomeClassBuilder(mandatoryField, mandatoryString);
}
}
}

Then you call it with:
SomeClass some = SomeClass.withMandatoryField(5).withMandatoryString(“hello”).withOptionalField(true).build();

The only problem with this approach is that you need one Builder class for each mandatory parameter and those classes needs to be visible to the calling code. But hey, it’s safe!

16 04 2012
lukaseder

You might be interested in this reading here:
http://blog.jooq.org/2012/01/05/the-java-fluent-api-designer-crash-course/

I have recently documented some basic rules of transforming any arbitrary BNF syntax structure into a Java API. This might also apply to what you call the builder or initialiser pattern

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




Follow

Get every new post delivered to your Inbox.

%d bloggers like this: