Java - Inherited Fluent method return type to return incident class' type, not parent's

fluent, inheritance, java

Solution

You can do it like this, if you don't mind an unchecked cast:

public class Foo<T, F extends Foo<T, F>> {
  public F someMethod() {
    System.out.println("foo");
    return (F) this; // <--- That's the unchecked cast! Tucked safely away.
  }
  public static void main(String[] args) {
    new Bar<String>().someMethod().barMethod();
  }
}

class Bar<T> extends Foo<T, Bar<T>> {
  public Bar<T> barMethod() {
    System.out.println("bar");
    return this;
  }
}

Personally, I disable the unchecked cast warning globally for the whole project.

Problem

When you employ a fluent approach you might have the following scenario: ``` public class Foo<T extends a>{ public Foo<T> someMethod(){ System.out.println("foo"); return this; } } public class Bar<T extends b> extends Foo<T> { public Bar<T> barMethod(){ System.out.println("bar"); return this; } } public class a{} public class b extends a{} ``` A strength of a fluent interface is that you can chain method invocations, but whilst Bar has inherited someMethod(), the return type is Foo not Bar which would break the following chain: ``` new Bar<b>().someMethod().barMethod(); ``` One answer could be to add @Overrides for every inherited method, such that Bar has the additional method: ``` @Override public Bar<T> someMethod(){ System.out.println("foo"); return this; } ``` But in large classes, and extended class hierarchies this can prove a mess of redundancy surely?! Is there an appropriate return type to give to fluent methods whereby every class that inherits it will return an object of its specific type (so that we can chain methods without casts)? I tried: ``` public <U extends Foo<T>> U someMethod(){ System.out.println("foo"); return this; } ``` To alas, no avail. I am hoping someone knows of a simple and elegant solution to this problem. The project is large and so it needs to be maintainable and extensible if possible. Thank you to any help you can provide in this scenario.

Original source