Search code examples
javagenericstype-parameter

How to replace a parameterized type with a more specific one


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?


Solution

  • Using the following signature:

    <W extends V> SuperType<W, ?> doMoreSpecific(Class<W> typeToken);
    

    There might be some unsafe cases though that I have not been able to find yet, any criticism is welcome!