judokaine
judokaine

Reputation: 61

Java generic class of another generic class

I have a base generic class representing all objects of my model that have an identifier of whatever type:

public abstract class IdObject<T> {
    private T    id;
    public  T    getId()     { return this.id; }
    public  void setId(T id) { this.id = id;   }
}

Then, I have an super-interface representing the DAO for those IdObject objects:

public interface IdObjectDAO<T extends IdObject<U>> {
    public T getObjectById(U id);
}

but I get the compiler error of "U cannot be resolved to a type". If I change the interface definition by:

public interface IdObjectDAO<T extends IdObject<U extends Object>> {...}

I get the compiler error of "Syntax error on token "extends", , expected". The only way to define the interface without compiler errors is:

public interface IdObjectDAO<T extends IdObject<? extends Object>> {...}

but then I don't have a type alias (U) for the public T getObjectId(U id) method. The only solution I've found to solve it is using 2 type parameters:

public interface IdObjectDAO<T extends IdObject<U>, U> {...}

but I want to avoid using those 2 type parameters to avoid specifying the identifier type in model and DAO classes:

public class     Person    extends IdObject<Integer> {...}
public interface PersonDAO extends IdObjectDAO<Person, Integer> {...}
                                                     ^^^^^^^^^ <== avoid this

Can anybody think in another way to implement this generic of generic or define the IdObjectDAO interface?

Thanks in advance!

Upvotes: 6

Views: 1499

Answers (1)

Vincent van der Weele
Vincent van der Weele

Reputation: 13177

An interface is not just defined by its name, it consists of the signatures of all methods defined in it. Since you have the method

public T getObjectById(U id);

your interface is generic in both T and U. There is no way for the interface to determine U from IdObject<U>, so you'll have to specify it explicitly if you want compile time type safety.

If you really insist on only providing T as a generic parameter, the two (pretty bad) workarounds I can come up with are:

1) Lose type safety:

public interface IdObjectDAO<T extends IdObject<?>> {
    public T getObjectById(Object id);
}

If you implement equals of U correctly, you can still successfully call

id.equals(t.getId());

for an object t of type T.

2) Wrap your id in an object of type T:

public interface IdObjectDAO<T extends IdObject<?>> {
    public T getObjectBySample(T sample);
}

You can call this like:

Integer id = 5;
Person sample = new Person(id);
Person object = personDao.getObjectBySample(sample);

Upvotes: 1

Related Questions