Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic constructor (Class<T> clazz) do not support T where T is another generics

Tags:

java

generics

Imagine this class:

public class ObjectCreator<T> {
    private Class<T> persistentClass;

    public ObjectCreator(Class<T> persistentClass) {
        this.persistentClass = persistentClass;
    }

    public T create() {
        T instance = null;
        try {
            instance = persistentClass.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        } 

        return instance;
    }
}

Now I sublclass it with a domain object:

public class PersonCreator extends ObjectCreator<Person>{

    /**
     * @param persistentClass
     */
    public PersonCreator() {
        super(Person.class);

    }

}

All works great... But if I try to subclass it with a another generic domain object the compiler complains:

public class MessageCreator extends ObjectCreator<Message<String>>{

    /**
     * @param persistentClass
     */
    public MessageCreator() {
        super(Message.class);
    }

}

The constructor ObjectCreator<Message<String>>(Class<Message>) is undefined MessageCreator.java

I think that this is a big limit: why is this forbidden?

Any idea how to work around?

Massimo

like image 527
Massimo Ugues Avatar asked Jan 12 '13 17:01

Massimo Ugues


2 Answers

Try this:

super((Class<Message<String>>) ((Object) Message.class)); //compiles with warning

It will be even better if you'll change constructor of base class to

public ObjectCreator(Class<? extends T> persistentClass)

and then use this in derrived classes:

super(new Message<String>(){}.getClass()); //compiles without warning

It will compile without warnings

EDIT

According to definition of getClass() http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#getClass()

Returns Class<? extends X>, where X is the erasure of the static type of the expression on which getClass is called. Which means getClass() will return Class<? extends Message> for new Message<String>() and Class<? extends Message<String>> for anonymous class new Message<String>(){}

like image 108
Dmitry Zaytsev Avatar answered Oct 22 '22 19:10

Dmitry Zaytsev


There is no '.class' variant for generic classes - the information is not available at runtime, hovewever in order to make the above code compile, you can simply cast the expression to the required type.

super ((Class<Message<String>>)((Class<?>)Message.class));

Note that this will not make the information available at runtime either (i.e. for reflection, etc.), however it should compile with an unchecked warning - which is just that - a warning.

like image 41
Sebastian Avatar answered Oct 22 '22 20:10

Sebastian