Reputation: 732
This is a follow up to: my previous question
My following line of code does not work:
IAccount account = (AccountModel) new AccountRepository().getByEmail(emailaddress);
The returntype of ...getByEmail(...)
is Model<Account>
, and AccountModel
extends Model<Account>
.
Yet I get a java.lang.ClassCastException: models.Model cannot be cast to models.AccountModel
when I test it. I know this is because every AccountModel
is a Model<Account>
, but not the other way around.
Is there any way how I can make sure that I can fix this (or work around it).
public class AccountRepository extends Repository<Account> {
public AccountRepository() {
super(Account.class);
}
public Model<Account> getByEmail(String emailAddress) {
return this.getCustomHqlSingle("FROM Account a WHERE a.emailAddress = '" + emailAddress + "'");
}
}
public abstract class Repository<T> implements Serializable {
protected final Model<T> getCustomHqlSingle(String hql) {
List<Model<T>> t = this.getCustomHqlList(hql);
if (t != null && !t.isEmpty()) {
return t.get(0);
} else {
return null;
}
}
protected final List<Model<T>> getCustomHqlList(String hql) {
Session session = SESSION_FACTORY.openSession();
try {
session.beginTransaction();
List<T> entities = session.createQuery(hql).getResultList();
List<Model<T>> result = new ArrayList<>();
for (T t : entities) {
result.add(this.getByEntity(t));
}
return result;
} finally {
session.close();
}
}
To the person that marked this question as duplicate, let me rephrase the following sentence from my question:
I know this is because every
AccountModel
is aModel<Account>
, but not the other way around.
To
I know this is because every
Dog
is anAnimal
, but not the other way around.
Upvotes: 0
Views: 1347
Reputation: 33845
You have to devise a method in which to convert a Model<Account>
to an AccountModel
. Taking the code from your other question you could add a constructor for this to the AccountModel
class:
public class AccountModel extends Model<Account> implements IAccount {
private static final AccountRepository REPOSITORY = new AccountRepository();
public AccountModel(Account entity) {
super(entity, REPOSITORY);
}
public AccountModel(Model<Account> model) { // <---
super(model._entity, REPOSITORY);
}
// Method implementations...
}
Then change your AccountRepository
class to return an AccountModel
from getByEmail
:
public AccountModel getByEmail(String emailAddress) {
return new AccountModel(this.getCustomHqlSingle("FROM Account a WHERE a.emailAddress = '" + emailAddress + "'"));
}
Which uses the new constructor to convert the Model<Account>
to an AccountModel
.
There is another option. Rather than calling new Model<T>(...)
in Repository
, you could have implementing classes implement an abstract method that would return the desired Model
type:
public abstract class Repository<T, R> implements Serializable
...
public Repository(Class<T> repositoryClass) {
if (!Repository._initiated)
setup();
this.cons = cons;
}
protected abstract R getModel(T entity, Repository<T> repo); // <--
Then somewhere in the factory methods:
public R getByFoo(...) {
...
T t = session.get(_repositoryClass, ...);
return getModel(t, this);
}
Where AccountRepository
would return a new AccountModel
:
public class AccountRepository extends Repository<Account, AccountModel> {
public AccountRepository() {
super(Account.class);
}
@Override
protected AccountModel getModel(Account entity, Repository<Account> repo) {
return new AccountModel(entity);
}
}
Upvotes: 1
Reputation: 13123
Since you say you understand why you get an error, let me try to explain something else about casting.
Except for some limited cases, the casting operator does not change the item being cast. Casting is an instruction to the compiler only, saying "My logic has guaranteed that the type of the cast object is different than the compiler can determine, so while you (the compiler) would tell me this is an error, I am certain that, at runtime, it will be fine. So don't give me an error".
It does NOT say "take this object and transform it into another, similar object". That operation is not possible in Java, thank heavens.
Upvotes: 0