Understanding the use of Generics in an abstract DAO Hibernate class

Asked

Viewed 517 times

1

Hello,

I am starting to develop a web application with spring+Hibernate framework, I started for an example that contained following class:

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;

public abstract class AbstractDao<PK extends Serializable, T> {

    private final Class<T> persistentClass;

    @SuppressWarnings("unchecked")
    public AbstractDao(){
        this.persistentClass =(Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
    }

    @Autowired
    private SessionFactory sessionFactory;

    protected Session getSession(){
        return sessionFactory.getCurrentSession();
    }

    @SuppressWarnings("unchecked")
    public T getByKey(PK key) {
        return (T) getSession().get(persistentClass, key);
    }

    public void persist(T entity) {
        getSession().persist(entity);
    }

    public void delete(T entity) {
        getSession().delete(entity);
    }

    protected Criteria createEntityCriteria(){
        return getSession().createCriteria(persistentClass);
    }

}

It is an abstract DAO to be used for the remaining Daos, I cannot understand the generics that the class receives:

public abstract class AbstractDao<PK extends Serializable, T> 

And the line that’s on the builder

this.persistentClass =(Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];

I’m not comfortable with java generics. They can help explain the logic of this class?

Thank you.

  • The line you found complicated is a gambit to circumvent the type Erasure Java. Because Java deletes generic type information, this gambit is necessary to know which one it is.

2 answers

0

These will be types declared by the classes that will extend your DAO.

Suppose you create a concrete DAO to work with an entity Book. He should be declared to be foma-like:

public class BookDao extends AbstractDao<Long, Book> {
    ...
}

All references to types PK and T now they’ll be the guys Long and Book, respectively. And the following code shall be valid:

BookDao bookDao = new BookDao();
Book myBook = bookDao.getByKey(100); // Aqui, getByKey aceita um Long e retorna um Book

It is the same concept used with List and Map, for example. To create a ArrayList String, you must invoke:

List<String> strings = new ArrayList<String>();
// O metodo add recebera somente strings agora
strings.add("Hello");

If you search the source of the class List, you will see that it has been declared generic:

public interface List<E> extends Collection<E> {
    ...
}

The constructor line is a way to search, at runtime, for the generic type class T.

0


Hello,

This class is this way so that new Daos can pass different entities to extend this class and thus reuse the methods of this abstract class.

For example, if you have an entity Pedido (T), in which the primary key (PK) is an object of the type Long and want to create a DAO for her, the code would be:

class PedidoDao extends AbstractDao<Long, Pedido> {

}

After this, you can use in the class PedidoDao the methods of AbstractDao, and all will adhere to the particularity of its entity Pedido.

About the specific code of the manufacturer:

this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];

The first part:

(ParameterizedType) this.getClass().getGenericSuperclass()

It is used to take the parameterizable class type (ParameterizedType), containing information from PK and T. But how the code wants to catch the entity T, he uses:

getActualTypeArguments()[1]

For in position [0] is the PK.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.