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!