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.
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.
What you can do is define barMethod
method abstract so now you can call it on the Foo
type.
public abstract class Foo<T extends a> {
public Foo<T> someMethod() {
System.out.println("foo");
return this;
}
public abstract Foo<T> barMethod();
}
Now you can easily call
new Bar<b>().someMethod().barMethod();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With