Although I tagged this question as a Morphia issue, I think it's more general, but anyway, help is appreciated.
I have IUser interface that I don't have control over it:
public interface IUser<T> {
...
public String getFirstName();
...
}
I, also, have an implementation User (Morphia entity) of this interface:
@Entity
public class User implements IUser<ObjectId> {
@Id
private ObjectId id;
@Property
private String firstName;
public String getFirstName() {
return this.firstName;
}
...
}
When Morphia asks for the classes to be mapped, I provide User.class, since this is the Morphia entity. Therefore, when I extend the BasicDAO, I provide User and ObjectId as types:
public class UserDAO extends MongoDAO<User, ObjectId> {
public List<IUser<ObjectId>> getUsers(String id) {
return ds.find(IUser.class, Mapper.ID_KEY, new ObjectId(id)).asList();
}
}
Now, the problem appears in the getUsers method. As you can see, I want to continue working with the interface outside this class; that's why I expect List<IUser<ObjectId>>
as a return type.
The first argument of the ds.find(...) method is a Class<T>
type, so I provide IUser.class. But, because of this, I cannot anymore expect List<IUser<ObjectId>>
as a result, but just List<IUser>
. This way, I have lost the type of IUser. Is it possible at all to force this Morphia's method to return a list of parameterized IUser objects?
Thank you in advance, Zlatko
There are a couple of options.
What Guava, Guice and similar libraries do is accept a TypeToken
which leverages an anonymous inner class to reify the types. It would look something like this:
return ds.find(new TypeToken<IUser<ObjectId>>(){}, ...);
But obviously that's not really an option here since you can't change the library. It is what I'd consider to be the correct solution however.
The second option is to just cast the class to contain the generic parameter. This results in an unchecked warning however that needs to be suppressed or ignored:
@SuppressWarnings({"unchecked"})
Class<IUser<ObjectId>> userClass = (Class<IUser<ObjectId>>) (Object) IUser.class;
return ds.find(userClass, ...);
It should really be noted that the suggestion above is really no better than just casting the entire list from a List<IUser>
to a List<IUser<ObjectID>>
before returning it. Both carry the same need to suppress warnings.