简体   繁体   中英

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?

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);
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM