Emulating "self types" using Java Generics to simplify fluent API implementation

The Java programming language does not support the notion of "self types", that is "type of this". When implementing fluent APIs, this lack of support can lead to significant duplication of boilerplate code. Taking FEST Assertions as an example, this article shows how "self types" can be emulated in Java using Generics.

Why bother?

FEST Assertions provide a beautiful API to write assertions in Java code:

  Collection<Item> myItems = orderService.getItems(orderId);
  assertThat(myItems).isNotNull().contains(expectedItem);

assertThat() acts as an overloaded factory for Assertion objects of different type. There are roughly 34 XxxAssert classes in FEST-Assert 1.x at the time of writing. Each of these classes implement a number of assertion methods, which check whether the actual value myItems satisfies the condition indicated by the method's name, like isNotNull or contains. If the check fails, the methods throw an AssertionError, otherwise they return this to allow chaining of method calls in a fluent manner.

Let's take CollectionAssert as an example. It provides both isNotNull() and contains(). The relevant method signatures look like this:

public class CollectionAssert /* ... */ {

  @Override public CollectionAssert isNotNull() {
    assertNotNull();
    return this;
  }

  @Override public CollectionAssert contains(Object... objects) {
    assertContains(objects);
    return this;
  }

You might ask why isNotNull() is implemented in class CollectionAssert, and not in some more generic superclass? If it's in CollectionAssert, is it also in all the other concrete assertion classes? Bad news is: yes, it is.

Return type is vital for access to fluent API methods

Of course, there actually is a superclass which might be a candidate to move the implementation of isNotNull() into, it's called GenericAssert. In it, we find:

public abstract class GenericAssert<T> /* ... */ {

  protected abstract GenericAssert<T> isNotNull();
}

This method is declared abstract, and it has 31 concrete implementations. They all look nearly the same:

  // from class BigDecimalAssert:
  @Override public BigDecimalAssert isNotNull() {
    assertNotNull();
    return this;
  }

  // from class FileAssert:
  @Override public FileAssert isNotNull() {
    assertNotNull();
    return this;
  }

  // from class ImageAssert:
  @Override public ImageAssert isNotNull() {
    assertNotNull();
    return this;
  }

  // many more, all looking alike... 

The only thing wich differs is the return type, which is always the class implementing the overridden isNotNull. This is necessary because otherwise it would not be possible to add methods to a call chain which are defined in the concrete assertion class, but not in the more generic superclass where isNotNull is implemented. If we moved the concrete implementation to GenericAssert, we would get a GenericAssert instance as return value of isNotNull(), and GenericAssert certainly does not provide contains (as CollectionAssert does) or isDirectory (as FileAssert does). So the following code would not compile any more:

  assertThat(actualCollection).isNotNull().contains(expectedItem); 
  assertThat(actualFile).isNotNull().isDirectory();

Possible solution: spend more effort - write more code

The current codebase of FEST Assertions deals with this problem by adding a tiny overridden method to each concrete subclass. The only purpose is to return the correct, most specialized type after checking that the condition holds. This is always the class overriding the assertion method, as one can easily see from the examples above. Some programming language adepts call them covariant method overrides to be cool.

The main problem with this approach is code duplication and all its aftermath.

Next try: spend more effort, think up DRY solution

Wouldn't it be great to implement each assertion method exactly once, and rely on Java language mechanisms to make sure that each method returns the concrete implementation class automatically?

Thanks to a prolific discussion with one of my colleagues (kudos go out to ASc), in which we thought up the basic ideas to tackle this problem with Java generics, I'm in the lucky position to explain our solution to you.

Generics to the rescue...

The most fundamental part of the solution is to pass SELF_TYPE as type parameter to each (super) type which declares assertion methods. As an example, let's compare the two different variants of GenericAssert, without and with SELF_TYPE:


// without SELF_TYPE

public abstract class GenericAssert<ELEMENT_TYPE> extends Assert {

  protected final ELEMENT_TYPE actual;

  protected GenericAssert(ELEMENT_TYPE actual) {
    this.actual = actual;
  }

  // ...

  protected abstract GenericAssert<ELEMENT_TYPE> isNotNull();

  // ...

}

How to actually introduce SELF_TYPE into the code?

Now we change this to:


// WITH SELF_TYPE

public abstract class GenericAssert<
  SELF_TYPE extends GenericAssert<SELF_TYPE, ELEMENT_TYPE>,
  ELEMENT_TYPE
> 
extends Assert {

  protected final ELEMENT_TYPE actual;

  @SuppressWarnings("unchecked")    
  protected final SELF_TYPE self() {
    return (SELF_TYPE) this;
  }

  protected GenericAssert(ELEMENT_TYPE actual) {
    this.actual = actual;
  }

  public final SELF_TYPE isNotNull() {
    failIfActualIsNull(customErrorMessage(), rawDescription(), actual);
    return self();
  }

  // ...

}

There are a few things to notice:

  • We introduced a new type parameter called SELF_TYPE, which must fullfill SELF_TYPE extends GenericAssert<SELF_TYPE, ELEMENT_TYPE>. This ensures that concrete generic instances must extend the currently defined class GenericAssert, in other words: only subclasses of GenericAssert are allowed as SELF_TYPE. This is sometimes called a self-bounded generic. Here, GenericAssert is self-bounded in SELF_TYPE.
  • We introduced a new final method self(), which basically just returns this cast to SELF_TYPE.
  • The assertion method's implementation is not abstract any more, instead, we declare it to return SELF_TYPE. The implementation calls the relevant check code and returns self().
  • The self() method is a very convenient way of returning this, but with a cast to the correct return type already applied.
  • Since SELF_TYPE is a type variable, this could be any matching type a derived class might potentially pass as the type variable's value.

Defining concrete implementation classes

This is where the whole effort really pays off. Let's look at a variant of FileAssert which exploits the SELF_TYPE in GenericAssert:


// SELF_TYPE is set to FileAssert here:
public class FileAssert extends GenericAssert<FileAssert, File> {

  // NO overriden isNotNull method any more!
  // We can use the inherited one!

  // same is true for *all* of the protected abstract
  // assertion methods in *all* of the classes derived 
  // from GenericAssert!

}

How much can we gain?

The inherited methods are of course still there, the only thing is we don't need to re-implement them in each and every concrete subclass. This saves a great deal of boilerplate code. For example, the original version of GenericAssert contained 14 protected abstract assertion methods, which had to be implemented in each of the 34 concrete subclasses. This sums up to 476 methods which are not required any more and existed purely to support the fluent API syntax. And this is only for GenericAssert, there are certainly some more occurrences of protected abstract methods which had to be overridden in each concrete subclass for exactly the same purpose!

This is a huge number of methods which could be dropped from the code, or for new assertion methods, never need to be written nor maintained.

Does my IDE still support code completion?

Since we merely removed specialized methods, keeping the super class's implementation, the answer is "yes", of course! To prove it, have a look at this IntelliJ IDEA screenshot, showing some test code of FileAssert:

As you can see, the return type of all the assertion methods like isNotNull() in the concrete class automatically gets substituted with the concrete class name (FileAssert in this case).

Resources

I refactored GenericAssert of the FEST-Assert 1.3 codebase as described above. It's available on github: emulate-self-type branch.

What's next?

Feel free to have a look at the complete code at github, referenced above.

Please let me know what you think about this idea. Should we possibly use this approach for the next major version 2.x of FEST-Assert, which is currently in a very early design stage? Would you mind at all?

Curiously recurring template pattern

This reminds me of the "Curiously recurring template pattern".

Linking pattern description for reference

Hi Jonatan, thanks for sharing this.

Indeed, the CRTP looks very similar. Quote from http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

a class X derives from a class template instantiation using X itself as template argument.

AFAICS, that's roughly the C++ equivalent of the Java technique used here.

Best regards,

Ansgar

Even more simple

Why not skip the self() method and just cast the return object immediately? Like this:


public final SELF_TYPE isNotNull() {
failIfActualIsNull(customErrorMessage(), rawDescription(), actual);
return (SELF_TYPE)this;
}

Simplicity vs. Convenience

Hi Misja,

thanks for commenting. You are right. Of course you could also drop the self() method and write (SELF_TYPE) this in each method. As I tend to be a lazy guy, I like saving a few extra keystrokes while typing, thus the self() method.

Best regards

Ansgar

Brilliant article

I wish this technique was taught in every generics tutorial...
It could also be a nice thing if a typed class could return an instance of its self type using a keyword at the language level....

What if GenericAssert was not abstract?

Very interesting idea!

I tried adding it to Metawidget, which has a class BaseXmlInspectorConfig and methods like setInputStream. So now I have:

public class BaseXmlInspectorConfig<SELF_TYPE extends BaseXmlInspectorConfig<SELF_TYPE>>
...
public SELF_TYPE setInputStream( InputStream stream )
...

But my scenario is slightly different because my base class (BaseXmlInspectorConfig) is not abstract (your GenericAssert is). When I try to instantiate BaseXmlInspectorConfig, I have a problem. This line gives a warning:

BaseXmlInspectorConfig config = new BaseXmlInspectorConfig();

As does this:

BaseXmlInspectorConfig<?> config = new BaseXmlInspectorConfig();

This gives an error:

BaseXmlInspectorConfig<?> config = new BaseXmlInspectorConfig<?>();

As does this:

BaseXmlInspectorConfig<?> config = new BaseXmlInspectorConfig<BaseXmlInspectorConfig>();

So is there a good way to instantiate these things? Or does the base class have to be abstract?

Regards,

Richard.

Instantiating non-abstract classes

Hi Richard,

when instantiating BaseXmlInspectorConfig, you have to pass the "self type", like so:

BaseXmlInspectorConfig<BaseXmlInspectorConfig> config = new BaseXmlInspectorConfig<BaseXmlInspectorConfig>();

Or, see this tiny example:

public class MyClass<SELF_TYPE extends MyClass> {
  
  public SELF_TYPE myMethod() {return (SELF_TYPE) this;}
  
  public void main(String[] args) {
    MyClass<MyClass> myInstance = new MyClass<MyClass>();
    myInstance.myMethod().myMethod().myMethod().myMethod();
  }

}

Looks a bit strange at first sight, but works :-)

Regards

Ansgar

Instantiating non-abstract classes

Ansgar,

Thanks for your reply! I'm afraid your example doesn't work for me. In your version you have actually left off part of your own solution (accidentally, I'm sure!). I think line 1 is meant to be:

public class MyClass<SELF_TYPE extends MyClass<SELF_TYPE>>

Without this you get a compiler warning. But as soon as you add the extra SELF_TYPE, I can't figure out how to instantiate it on line 6? All of the variants seem to give an error.

Richard.

Instantiating non-abstract classes

Hi Richard,

you are right. It seems to be a requirement that one has to derive from the generic class first, and then use the concrete subclass. With that subclass, it is *also* possible to create instances of the generic class which are inconsistent wrt their "self type", and thus result in ClassCastExceptions at return (SELF_TYPE) this;

class MyClass<SELF_TYPE extends MyClass<SELF_TYPE>> {
  public SELF_TYPE myMethod() {
    System.out.println("My Method: " + this.getClass().getSimpleName());
    return (SELF_TYPE) this;
  }
}

class MyClass2 extends MyClass<MyClass2> {
  public void finalMethod() {
    System.out.println("Final.");
  }
}

public class Test {

  public static void main(String[] args) {
    MyClass2 myInstance = new MyClass2();
    myInstance.myMethod().myMethod().myMethod().myMethod();  // works

    MyClass<MyClass2> myInstance2 = new MyClass<MyClass2>(); 
    myInstance2.myMethod().finalMethod();                    // will result in ClassCastException
  }

}

Regards

Ansgar

Instantiating non-abstract classes

Ansgar,

Hmmm. Okay, given this additional complexity I guess there comes a 'tipping point' for this technique when its advantages outweight its disadvantages.

I think for Metawidget, which has a non-abstract base class with few fluent methods, it becomes too cumbersome. For FEST Assertions, which has an abstract base class with dozens of fluent methods, it may make more sense. So on balance I don't think I'll adopt it just now.

Which is not to take away, of course, from the great work you have done here and the new idea you have introduced into the Java community. Your idea reminds me of Gafter's Gadget as an innovative use of generics. Well done!

Regards,

Richard.

Rather whan adding filed

Rather whan adding filed (which consumes some memory) I'd better add method

protected SELF_TYPE self() {
  @SuppressWarnings("unchecked")
  return (SELF_TYPE) this;
}
public final SELF_TYPE isNotNull() {
  failIfActualIsNull(customErrorMessage(), rawDescription(), actual);
  return self();
}

Good idea!

Thanks for commenting. Indeed a good idea. I'll update the post accordingly.

Ansgar