Understand the use of generics in an abstract class DAO Hibernate

1

Hello,

I'm starting to develop a web application with spring + hibernate framework, I started with an example that contained the 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 can not understand the generics the class receives:

public abstract class AbstractDao<PK extends Serializable, T> 

And the line that is in the constructor

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

I'm not comfortable with generics in java. Can you give a help explain the logic of this class?

Thank you.

    
asked by anonymous 24.04.2018 / 22:10

2 answers

0

Hello,

This class is in 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 ), where the primary key ( PK ) is an object of type Long and you want to create a DAO for it, the code would look like:

class PedidoDao extends AbstractDao<Long, Pedido> {

}

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

About the builder-specific code:

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

The first part:

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

It is used to get the type of parameterizable class ( ParameterizedType ), which contains information for PK and T . But since the code wants to get the T entity, it uses:

getActualTypeArguments()[1]

Because in position [0] is PK .

    
24.04.2018 / 22:27
0

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

Suppose you create a concrete DAO to work with a Book entity. It should be declared similar to:

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

All references to types PK and T will now be of type Long and Book , respectively. And the following code snippet will be valid:

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

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

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

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

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

The constructor line is a way to look up, at runtime, the class of generic type T .

    
24.04.2018 / 22:27