Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a generic DAO for JPA that I can inherit from

I am trying to create a repository class that I can inherit from to get basic CRUD functionality from. The EntityManager.find(..) needs a Class argument. However, you can't pass T to it (By some reason I don't understand yet...type erasure). So I found the method that returns the entity class and added it from another question I saw. First of all, how does it work and second would it have much impact on performace? I see it use reflection.

@Stateless
public abstract class AbstractSqlRepository<T> implements Repository<T> {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public void create(T entity) {
        entityManager.persist(entity);
    }

    @Override
    public T find(int id) {
        return entityManager.find(getEntityClass(), id);
    }

    @Override
    public T update(T entity) {
        return entityManager.merge(entity);
    }

    @Override
    public void remove(T entity) {
        entityManager.remove(entity);
    }

    public EntityManager getEntityManager() {
        return entityManager;
    }

    public Class<T> getEntityClass() {
        ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();

        return (Class<T>) genericSuperclass.getActualTypeArguments()[0];
    }
}

New approach:

@Stateless
public abstract class AbstractSqlRepository<T> implements Repository<T> {

    @PersistenceContext
    private EntityManager entityManager;
    private Class<T> clazz;

    public AbstractSqlRepository(Class<T> clazz) {
        this.clazz = clazz;
    }

    @Override
    public void create(T entity) {
        entityManager.persist(entity);
    }

    @Override
    public T find(int id) {
        return entityManager.find(clazz, id);
    }

    @Override
    public T update(T entity) {
        return entityManager.merge(entity);
    }

    @Override
    public void remove(T entity) {
        entityManager.remove(entity);
    }

    public EntityManager getEntityManager() {
        return entityManager;
    }
}

and

public class QuestionSqlRepository extends AbstractSqlRepository implements QuestionRepository {

public QuestionSqlRepository() {
    super(Question.class);
}

}

Is this a bad approach?

like image 525
LuckyLuke Avatar asked Nov 03 '22 13:11

LuckyLuke


1 Answers

It is stated that reflection will add overhead but you don't have to get the Class of the object every time in my opinion.

Just find it the first time and check for null afterwards, this adds very little overhead compared to call a super class method.

The only argument against the constructor parameter is that your class won't be a POJO.

Here is the sample code:

@SuppressWarnings("unchecked")
public class HibernateBaseDao<T, Pk extends Serializable> implements Dao<Pk, T> {

    // ...
    private Class<T> type;

    // ...

    public Class<T> getType() {

        if (this.type == null) {

            ParameterizedType parameterizedType = (ParameterizedType) (this
                    .getClass().getGenericSuperclass());

            while (!(parameterizedType instanceof ParameterizedType)) {
                parameterizedType = (ParameterizedType) parameterizedType
                        .getClass().getGenericSuperclass();
            }

            this.type = (Class<T>) parameterizedType.getActualTypeArguments()[0];

        }

        return this.type;
    }

    @Override
    public T load(Pk id) {

        return (T) this.sessionFactory.getCurrentSession().load(this.getType(),
                id);
    }

    @Override
    public T get(Pk id) {
        return (T) this.sessionFactory.getCurrentSession().get(this.getType(),
                id);
    }

}
like image 188
ElderMael Avatar answered Nov 12 '22 11:11

ElderMael