Consider the following setup:
We have an interface SuperType which is parameterized like this:
public interface SuperType<V> {
}
SuperType supports method chaining. Hence it defines another type parameter which captures the concrete implementing subtype returned by each method like this:
public interface SuperType<V, S extends SuperType<V, S>> {
public S doSomething();
}
Let's consider an implementation of SuperType<V, S extends SuperType<V, S>>:
public class SubType<V> implements SuperType<V, SubType<V>> {
private final V value;
public SubType(V value) { this.value = value; }
public SubType<V> doSomething() { return this; }
}
Someone instantiates SubType<V> using for example strings but provides Object for the type parameter V:
Object s = "Java Generics";
SubType<Object> x = new SubType<>(s);
Now we want to define another method for SuperType<V, S extends SuperType<V, S>> which takes a more specific type parameter of V and returns the same implementation type S but now parameterized with W extends V:
public interface SuperType<V, S extends SuperType<V, S>> {
public S doSomething();
public <W extends V, T extends SuperType<W, T>> T doMoreSpecific(Class<W> typeToken);
}
This new interface definition is intended to support:
Object s = "Java Generics";
SubType<Object> x = new SubType<>(s);
SubType<String> y = x.doMoreSpecific(String.class);
Here I struggle to implement SubType<V>. What I want to provide as an implementation is:
public class SubType<V> implements SuperType<V, SubType<V>> {
private final V value;
public SubType(V value) { this.value = value; }
public SubType<V> doSomething() { return this; };
public <W extends V> SubType<W> doMoreSpecific(Class<W> typeToken) {
return new SubType<>((W) value);
}
}
My Question is:
How should I define the signature for the method doMoreSpecific() in the type SuperType<V, S extends SuperType<V, S>> so that the implementation provided by
SubType<V> implements SuperType<V, SubType<V>> is acceptable?
Or otherwise, which implementation and interface method definition would do the trick?
Or else, why can't we do this in Java?
Using the following signature:
There might be some unsafe cases though that I have not been able to find yet, any criticism is welcome!