Gonzalo Calvo
Gonzalo Calvo

Reputation: 314

Limitation extending generics in java, any way to get around it?

I have the following model to make controllers in my application. Obviously, the full model is more complex but I will focus on the only part that is causing me problems:

public abstract AbstractController<T> {
    abstract protected Class<T> getType();
}

public ParentController extends AbstractController<Parent> {
    @Override
    protected Class<Parent> getType() {
        return Parent.class;
    }
}

Now I would like to extend the Parent object and have a controller for the son, it would look like this:

public SonController extends ParentController {
    @Override
    protected Class<Son> getType() {
        return Son.class;
    }
}

The problem is that the method getType() shows incompatibility in compilation (expects the class Parent).

I tried to play around with the generics but I can't find a solution. The method getType is used in several methods from the abstract controller and I would really like to avoid overriding those.

Any ideas would be wellcome.

Upvotes: 8

Views: 105

Answers (2)

Eugene
Eugene

Reputation: 120848

Generics are invariant to begin with, so Class<Son> can not be assigned to Class<Parent> (in your case these are not covariant return types).

But wildcard with an extends-bound (upper bound) makes the type covariant, thus this would solve it:

public abstract class AbstractController<T> {
    abstract protected Class<? extends T> getType();
}

public class ParentController extends AbstractController<Parent> {
    @Override
    protected Class<? extends Parent> getType() {
        return Parent.class;
    }
}

class SonController extends ParentController {
    @Override
    protected Class<? extends Parent> getType() {
        return Son.class;
    }
}

Upvotes: 5

Thiyagu
Thiyagu

Reputation: 17880

You could change the getType return Class<? extends T>.

abstract protected Class<? extends T> getType();

Then ParentController and SonController would look like

public class ParentController extends AbstractController<Parent> {
    @Override
    protected Class<? extends Parent> getType() {
        return Parent.class;
    }
}

public class SonController extends ParentController {
    @Override
    protected Class<? extends Parent> getType() {
        return Son.class;
    }
}

Upvotes: 6

Related Questions