wulfgarpro
wulfgarpro

Reputation: 6934

Generic type polymorphism confusion?

I have an abstract factory like so:

public abstract class DAOFactory {
    public abstract EntryDAO<EntryDTO> getEntryDAO();
    ...
}

With my DAO and DTO interfaces like so:

public interface EntryDTO extends GenericDTO {
}

public interface EntryDAO<T extends EntryDTO> extends GenericDAO<T, Serializable> {  
}

And my implementation like so:

public class EntryDTOImpl implements EntryDTO {
}

public class EntryDAOImpl<T extends EntryDTO> extends GenericDaoImpl<EntryDTOImpl, ObjectId> 
 implements EntryDAO<T> {
}

Now, if I create a factory and override the getEntryDAO method like so:

public class MyDAOFactory extends DAOFactory {   
    @Override
    public EntryDAO<EntryDTO> getEntryDAO() {
        try {
            return new EntryDAOImpl<EntryDTOImpl>();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

I get a compile time error:

Type mismatch: cannot convert from EntryDAOImpl to EntryDAO

EDIT

I've updated my abstract factory like so:

public abstract <T extends EntryDTO> EntryDAO<T> getEntryDAO();

And made the change in my factory implementation:

@Override
public <T extends EntryDTO> EntryDAO<T> getEntryDAO() {
    try {
        return new EntryDAOImpl<EntryDTOImpl>();
    } catch (UnknownHostException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

Now I'm getting the compile time error:

Type mismatch: cannot convert from EntryDAOImpl<EntryDTOImpl> to EntryDao<T>

Upvotes: 1

Views: 404

Answers (3)

Dawood ibn Kareem
Dawood ibn Kareem

Reputation: 79875

The reason this is happening is that you're trying to return an EntryDaoImpl<EntryDTOImpl>, which is a subtype of EntryDao<EntryDTOImpl>, but not of EntryDao<EntryDTO>, which is the return type of the method.

Solution:

I believe you want to change the return type of the getEntryDao method to

EntryDAO<? extends EntryDTO>.

Upvotes: 1

davidXYZ
davidXYZ

Reputation: 729

Define the abstract method this way (notice ? instead of T):

public abstract EntryDAO<? extends EntryDTO> getEntryDAO(); //should work for you

I recreated the scenario the way I understood it: returning subclass1<subclass2> as interface1<interface2>

For example, this works well:

public static List<? extends CharSequence> dostuff1() { 
    return new ArrayList<String>();
}

But this doesn't work:

public <B extends CharSequence> List<B> dostuff2() {
    return new ArrayList<String>();
}

This gives the same compile-time error that you got: Type mismatch: cannot convert from ArrayList<String> to List<B>

Upvotes: 2

Saintali
Saintali

Reputation: 4571

Just change the return type from EntryDao<T> to EntryDao<? extends T>. That will do the trick:

@Override
public <T extends EntryDto> EntryDao<? extends T> getEntryDao() {
    try {
        return new EntryDAOImpl<EntryDTOImpl>();
    } catch (UnknownHostException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return dao;
}

Now as a justification, suppose EntryDao<T> has methods that return T like

T load(Serializable id);

and methods that accept T like

void save(T t);

Now assume PersonDTO extends EntryDTO, and CarDTO extends EntryDTO.

If EntryDao<EntryDTO> were assignable from EntryDao<EntryDTOImpl>, it would also be assignable form EntryDao<PersonDTO> and EntryDao<CarDTO>.

Then you could do:

EntryDao<EntryDTO> x = new EntryDao<PersonDTO>();       // currently this is a compile time error

If that were legal, you could do:

x.save(new CarDTO());   // a run time error, because x can only save Persons, not Cars

But what is EntryDao<? extends EntryDTO>? It is just EntryDao with all T-accepting methods like save(T) removed.

Upvotes: 1

Related Questions