Generics: how to get type for reuse when using super?

I am trying to achieve type-savety across a method signature, but the type relation is lower-bound. I seem to need to use super T to restrict the type that the method parameter is restricted by. But I have no means to propagate the passed type to the method’s output parameter.

Basically here is what I would like to have:

class Bar {}

class Foo<T extends Bar> {

    // this works perfectly
    public <S extends T> Foo<S> from(S bar) {
        return new Foo<>(bar);
    }

    // incorrect syntax!
    // this should convert the current Foo into a Foo for a sub class ONLY
    public <U super T> Foo<U> fooing(Class<U> clazz) { // <-- this is what I need
        return new Foo<>(clazz);
    }
}

Sadly this is incorrect syntax. super can only be used with the wildcard operator ? in front.

The closest I could get was this:

public <U extends Bar> Foo<U> fooing(Class<? extends T> clazz) {...}

But it has some undesired effects:

class Bar2 extends Bar {}
...
Foo<Bar2> shouldFail = fooBar.fooing(Bar.class);  // Bar != Bar2
Foo<? extends Bar2> shouldFail2 = fooBar.fooing(Bar.class); // Bar does not extend Bar2

The above statements are valid. However I would like them to fail at compile time. Any ideas on how I can achieve what I need?

Here is a fiddle: http://ideone.com/scBFLc

Answer

As the Java Generics FAQ point out and you have experienced, that’s not really possible with class methods.

The workaround given by the FAQ is to use a static method:

public static <A extends Bar, B extends A> Foo<A> upcast(
        Foo<B> from, Class<A> target) { }

But I can only echo the concerns of the other commentators: you’re setting yourself up for some severe maintenance headaches, especially since I can’t envision an actual use case for this piece (in contrast to the FAQ example you’re only working on the Foo object, not adding to it).

Leave a Reply

Your email address will not be published. Required fields are marked *