Reputation: 9065
I am trying setting a generic class which will serve as base class for all my Dao classes in my application, but I am facing an error right now. My generic class is defined this way;
public class Dao<E> {
private final E entity;
@Autowired
SessionFactory sessionFactory;
protected Session getCurrentSession(){
return sessionFactory.getCurrentSession();
}
public Dao(E entity) {
this.entity = entity;
}
public E getEntity() {
return this.entity;
}
@Transactional
public boolean persist(E transientInstance) {
try {
sessionFactory.getCurrentSession().persist(transientInstance);
return true;
} catch (RuntimeException re) {
return false;
}
}
@Transactional
public boolean remove(E transientInstance) {
try {
sessionFactory.getCurrentSession().delete(transientInstance);
return true;
} catch (RuntimeException re) {
return false;
}
}
@SuppressWarnings("unchecked")
@Transactional
public E merge(E detachedInstance) {
try {
E result = (E) sessionFactory.getCurrentSession().merge(detachedInstance);
return result;
} catch (RuntimeException re) {
return null;
}
}
@Transactional
public E findById(int id) {
try {
E instance = (E) sessionFactory.getCurrentSession().get(E, id);
return instance;
} catch (RuntimeException re) {
return null;
}
}
@SuppressWarnings("unchecked")
@Transactional
public E findByUsername(String username) {
try {
E instance = (E) sessionFactory.getCurrentSession().createCriteria(E, username).add(Restrictions.like("login", username)).list().get(0);
return instance;
} catch (RuntimeException re) {
return null;
}
}
@SuppressWarnings("unchecked")
@Transactional
public List<E> findAll() {
try {
List<E> instance = sessionFactory.getCurrentSession().createCriteria(E).list();
return instance;
} catch (RuntimeException re) {
return null;
}
}
}
The methods with error are the last three, and is related to the referente to E by get() and createCriteria() in the implementation of them (the error is E cannot be resolved to a variable). Usually, I use something like 'Usuario.class' when I don't use this generic-based approach.
Anyone knows how to do fix this error in my generic class (if this approach is even possible).
Upvotes: 0
Views: 166
Reputation: 6540
Just adding on to the answer above. If you don't want to pass in arguments to your constructor you can do the following:
private Class<T> type;
public Dao(){
Type t = getClass().getGenericSuperclass();
ParameterizedType pt = (ParameterizedType) t;
type = (Class<T>) pt.getActualTypeArguments()[0];
}
and then reference type in your criteria when you are making queries.
Addendum: Remove your @Transactional
annotations from your DAO layer, @Transactional
belongs in your service layer
Upvotes: 0
Reputation: 8068
First of, the type parameter E
is not equal to an instance of Class
. And second, due to type erasure in Java everything about E is lost at runtime. But it seams that entity
passed in as a parameter to the constructor is the type token which to use when trying to ask for the class. Hence change the methods as follows:
@Transactional
public E findById(int id) {
try {
E instance = (E) sessionFactory.getCurrentSession().get(entity.getClass(), id);
return instance;
} catch (RuntimeException re) {
return null;
}
}
@SuppressWarnings("unchecked")
@Transactional
public E findByUsername(String username) {
try {
E instance = (E) sessionFactory.getCurrentSession().createCriteria(entity.getClass(), username).add(Restrictions.like("login", username)).list().get(0);
return instance;
} catch (RuntimeException re) {
return null;
}
}
@SuppressWarnings("unchecked")
@Transactional
public List<E> findAll() {
try {
List<E> instance = sessionFactory.getCurrentSession().createCriteria(entity.getClass()).list();
return instance;
} catch (RuntimeException re) {
return null;
}
}
or if entity
is not your type token, add a parameter Class<E> clazz
to the constructor like this:
private final E entity;
private final Class<E> clazz;
public Dao(E entity, Class<E> clazz) {
this.entity = entity;
this.clazz = clazz;
}
and use clazz
instead of entity.getClass()
in my suggested methods.
Upvotes: 1