Reputation: 49097
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?
Upvotes: 5
Views: 2773
Reputation: 7111
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);
}
}
Upvotes: 2