34

I'm trying to have an abstract base class for some builder classes so I can easily reuse code between the Builder implementations. I want my builders to support method chaining therefore a method has to return "this" instance of the most specific type. I figured I could probably do this with generics. Unfortunatly I did not manage to do it without using unsafe operations. Is it possible?

Sample code of how I'm trying it (and how it works) below. I'd like to avoid casting to T in "foo()" (which causes an unchecked warning), can this be done?

public class Builders
{
   public static void main( final String[] args )
   {
      new TheBuilder().foo().bar().build();
   }
}


abstract class AbstractBuilder<T extends AbstractBuilder<?>>
{
   public T foo()
   {
      // set some property
      return (T) this;
   }
}


class TheBuilder extends AbstractBuilder<TheBuilder>
{
   public TheBuilder bar()
   {
      // set some other property
      return this;
   }

   public Object build()
   {
      return new Object();
   }
}
Patrick Huy
  • 975
  • 1
  • 8
  • 19
  • One thing about the fluent interface idea is that there's this implicit assumption that all the methods return `this`, when legally they don't have to -- they could return a completely different object as long as it has the same return type. – Jason S Apr 28 '11 at 12:45
  • You just have to use javadoc. Either in an interface or in the abstract class. Users of the classes have to follow the contract provided by the javadoc. Theres not much more you can do as api designer (more ore less). – mike Aug 17 '13 at 00:03

3 Answers3

62

You want to declare T as extends AbstractBuilder<T> in AbstractBuilder.

Use an abstract protected method to get this of type T.

abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
    protected abstract T getThis();

    public T foo() {
        // set some property
        return getThis();
    }
}


class TheBuilder extends AbstractBuilder<TheBuilder> {
    @Override protected TheBuilder getThis() {
        return this;
    }
    ...
}

Alternatively, drop the generic type parameter, rely on covariant return types and make the code cleaner for clients (although usually they would be using TheBuilder rather than the largely implementation detail of the base class), if making the implementation more verbose.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • 4
    +1. I've done this before. I usually call it `me()` rather than `getThis()`, so that the end of the function reads `return me();` – Jason S Apr 28 '11 at 12:46
  • 3
    [Angelika Langer's FAQ: What is the "getThis" trick?](http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ206) – Paolo Fulgoni Mar 24 '14 at 15:55
  • @PaoloFulgoni And here's an earlier reference than hers (though slightly mangled by changes to the forum's rendering): https://www.java.net/node/643907 (second post) – Tom Hawtin - tackline Mar 24 '14 at 16:11
  • Thank you. First solution I've found without unchecked operations warnings. – stevehs17 Apr 08 '16 at 00:39
8

One alternative is not to use generics, but use overrides:

abstract class AbstractBuilder
{
   public AbstractBuilder foo()
   {
      // set some property
      return this;
   }
}

class TheBuilder extends AbstractBuilder
{
   @Override public TheBuilder foo()
   {
      super.foo(); return this;
   }
   public TheBuilder bar()
   {
      // set some other property
      return this;
   }

   public Object build()
   {
      return new Object();
   }
}
Jason S
  • 184,598
  • 164
  • 608
  • 970
  • 1
    This is the right way to go about it. This situation is the ideal case for inheritance and polymorphism. You worry about the builder, and the specific instance takes care of the details. I would make 1 change: have the AbstractBuilder implement an interface like Builder which defines the methods... this way you dont need to expose the default and abstract functionality as part of your API... sorry huge comment! – Java Drinker Apr 28 '11 at 12:43
  • 3
    Thanks, this works! Unfortunately my methods in these Builder classes tend to be rather small (they usually really only set a field, the build() method does the magic), thereby making the overriding solution seem overly verbose and it makes it cumbersome to implement new specific Builders (they always have to override ALL base class methods). – Patrick Huy Apr 28 '11 at 12:52
  • 2
    The draw back of this approach is every chained method in the AbstractBuilder must be Overridden in the subclass in order to return the subclass. The whole point of the getThis() trick is to avoid requiring that. – candied_orange Oct 10 '14 at 03:48
0

This should help:

abstract class AbstractBuilder<T extends AbstractBuilder<?>>
{
   public AbstractBuilder<T> foo()
   {
      // set some property
      return (AbstractBuilder<T>) this;
   }

   abstract AbstractBuilder<T> bar();
   abstract Object build();
}
Mike Thomsen
  • 36,828
  • 10
  • 60
  • 83
  • 1
    The problem I'm trying to solve is that different builder implementations produce different subclasses of a given interface i.e. all AbstractBuilders produce objects implementing IFoo, TheBuilder produces IFooBar and TheOtherBuilder produces IBarFoo. They have a different set of properties which can be populated by the specific builders. Sorry for not being clear about this in my original Question. You are of course right that build() should be a method on AbstractBuilder not on TheBuilder. – Patrick Huy Apr 28 '11 at 20:20