Kleber Mota
Kleber Mota

Reputation: 9065

Generic class for the Dao classes

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

Answers (2)

JamesENL
JamesENL

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

Harmlezz
Harmlezz

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

Related Questions