package fr.openwide.core.jpa.business.generic.dao; import java.util.Arrays; import java.util.List; import java.util.ListIterator; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.PersistenceException; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Order; import javax.persistence.criteria.Root; import javax.persistence.metamodel.SingularAttribute; import org.hibernate.Session; import com.querydsl.core.types.EntityPath; import com.querydsl.core.types.OrderSpecifier; import com.querydsl.core.types.Path; import com.querydsl.core.types.Predicate; import com.querydsl.core.types.dsl.ComparableEntityPath; import com.querydsl.core.types.dsl.Expressions; import com.querydsl.core.types.dsl.PathBuilder; import com.querydsl.core.types.dsl.StringPath; import com.querydsl.jpa.impl.JPAQuery; import fr.openwide.core.jpa.business.generic.model.GenericEntity; import fr.openwide.core.jpa.business.generic.model.QGenericEntity; public class JpaDaoSupport { @PersistenceContext private EntityManager entityManager; /** * @deprecated Utiliser QueryDSL. * * Crée la requête et applique les conditions de limite / offset et retourne la {@link TypedQuery} * correspondante. * * @param <T> le type de l'entité retournée * @param criteria * @param limit null si pas de limite * @param offset null si pas d'offset * @return la {@link TypedQuery} avec limite et offset le cas échéant */ @Deprecated protected <T> TypedQuery<T> buildTypedQuery(CriteriaQuery<T> criteria, Integer limit, Integer offset) { TypedQuery<T> query = getEntityManager().createQuery(criteria); if (offset != null) { query.setFirstResult(offset); } if (limit != null) { query.setMaxResults(limit); } return query; } /** * @deprecated Utiliser QueryDSL. */ @Deprecated protected void filterCriteriaQuery(CriteriaQuery<?> criteria, Expression<Boolean> filter) { if (filter != null) { javax.persistence.criteria.Predicate currentFilter = criteria.getRestriction(); if (currentFilter != null) { filter = getEntityManager().getCriteriaBuilder().and(currentFilter, filter); } criteria.where(filter); } } /** * @deprecated Utiliser QueryDSL. */ @Deprecated protected <T> Root<T> rootCriteriaQuery(CriteriaBuilder builder, CriteriaQuery<?> criteria, Class<T> objectClass) { return criteria.from(objectClass); } protected <T, K> T getEntity(Class<T> clazz, K id) { return getEntityManager().find(clazz, id); } public <T> T getEntityByNaturalId(Class<T> clazz, Object naturalId) { if (naturalId == null) { throw new IllegalArgumentException("Natural id may not be null"); } Session session = getEntityManager().unwrap(Session.class); return (T) session.bySimpleNaturalId(clazz).load(naturalId); } /** * @deprecated Utiliser QueryDSL. */ @Deprecated public <T, V extends Comparable<?>> T getEntityByField(Class<T> clazz, SingularAttribute<? super T, V> attribute, V fieldValue) { PathBuilder<T> entityPath = new PathBuilder<T>(clazz, "rootAlias"); return queryEntityByField(entityPath, attribute.getBindableJavaType(), attribute.getName(), fieldValue).fetchOne(); } protected <T, V extends Comparable<?>> JPAQuery<T> queryEntityByField(EntityPath<T> entityPath, Class<V> fieldClass, String fieldName, V fieldValue) { ComparableEntityPath<V> field = Expressions.comparableEntityPath(fieldClass, entityPath, fieldName); return queryByPredicate(entityPath, field.eq(fieldValue)); } /** * @deprecated Utiliser QueryDSL. */ @Deprecated public <T> T getEntityByFieldIgnoreCase(Class<T> clazz, SingularAttribute<? super T, String> attribute, String fieldValue) { PathBuilder<T> entityPath = new PathBuilder<T>(clazz, "rootAlias"); StringPath field = Expressions.stringPath(entityPath, attribute.getName()); return queryByPredicate(entityPath, field.equalsIgnoreCase(fieldValue)).fetchOne(); } protected <T> void update(T entity) { if (!getEntityManager().contains(entity)) { throw new PersistenceException("Updated entity must be attached"); } //TODO: http://blog.xebia.com/2009/03/23/jpa-implementation-patterns-saving-detached-entities/ } protected <T> void save(T entity) { getEntityManager().persist(entity); } protected <T> void delete(T entity) { getEntityManager().remove(entity); } protected <T> T refresh(T entity) { getEntityManager().refresh(entity); return entity; } public void flush() { getEntityManager().flush(); } public void clear() { getEntityManager().clear(); } // TODO : à refaire : il n'est pas possible de construire un filter ou un order stateless /** * @deprecated Utiliser QueryDSL */ @Deprecated protected <T> List<T> listEntity(Class<T> objectClass, Expression<Boolean> filter, Integer limit, Integer offset, Order... orders) { CriteriaBuilder builder = getEntityManager().getCriteriaBuilder(); CriteriaQuery<T> criteria = builder.createQuery(objectClass); rootCriteriaQuery(builder, criteria, objectClass); if (filter != null) { filterCriteriaQuery(criteria, filter); } if (orders != null && orders.length > 0) { criteria.orderBy(orders); } TypedQuery<T> query = buildTypedQuery(criteria, limit, offset); List<T> entities = query.getResultList(); if (orders == null || orders.length == 0) { sort(entities); } return entities; } public <T> List<T> listEntity(Class<T> objectClass) { PathBuilder<T> pathBuilder = new PathBuilder<T>(objectClass, "rootAlias"); OrderSpecifier<?> order = null; if (GenericEntity.class.isAssignableFrom(objectClass)) { // cast possible puisqu'on vient de vérifier le type de objectclass @SuppressWarnings("unchecked") QGenericEntity qGenericEntity = new QGenericEntity((Path<? extends GenericEntity<?, ?>>) (Object) pathBuilder); order = qGenericEntity.id.asc(); } return queryByPredicateOrdered(pathBuilder, null, order).fetch(); } /** * @deprecated Utiliser QueryDSL */ @Deprecated protected <T> List<T> listEntity(Class<T> objectClass, Expression<Boolean> filter) { return listEntity(objectClass, filter, null, null); } /** * @deprecated Utiliser QueryDSL */ @Deprecated protected <T, V extends Comparable<?>> List<T> listEntityByField(Class<T> objectClass, SingularAttribute<? super T, V> attribute, V fieldValue) { PathBuilder<T> entityPath = new PathBuilder<T>(objectClass, "rootAlias"); List<T> entities = queryEntityByField(entityPath, attribute.getBindableJavaType(), attribute.getName(), fieldValue).fetch(); sort(entities); return entities; } protected <T> Long countEntity(Class<T> clazz) { PathBuilder<T> entityPath = new PathBuilder<T>(clazz, "rootAlias"); return queryByPredicate(entityPath, null).distinct().fetchCount(); } /** * @deprecated Utiliser QueryDSL */ @Deprecated protected <T, V extends Comparable<?>> Long countEntityByField(Class<T> clazz, SingularAttribute<? super T, V> attribute, V fieldValue) { PathBuilder<T> entityPath = new PathBuilder<T>(clazz, "rootAlias"); return queryEntityByField(entityPath, attribute.getBindableJavaType(), attribute.getName(), fieldValue).distinct().fetchCount(); } /** * @deprecated Utiliser QueryDSL */ @Deprecated protected <T> Long countEntity(Class<T> clazz, Expression<Boolean> filter) { CriteriaBuilder builder = getEntityManager().getCriteriaBuilder(); CriteriaQuery<Long> criteria = builder.createQuery(Long.class); Root<T> root = rootCriteriaQuery(builder, criteria, clazz); criteria.select(builder.count(root)); filterCriteriaQuery(criteria, filter); return buildTypedQuery(criteria, null, null).getSingleResult(); } protected EntityManager getEntityManager() { return entityManager; } @SuppressWarnings("unchecked") protected <T> void sort(List<T> entities) { Object[] a = entities.toArray(); Arrays.sort(a); ListIterator<T> i = entities.listIterator(); for (int j = 0; j < a.length; j++) { i.next(); i.set((T) a[j]); } } protected <T> JPAQuery<T> queryByPredicateOrdered(EntityPath<T> entityPath, Predicate predicate, OrderSpecifier<?>... orderSpecifiers) { return queryByPredicateOrdered(entityPath, predicate, null, null, orderSpecifiers); } protected <T> JPAQuery<T> queryByPredicateOrdered(EntityPath<T> entityPath, Predicate predicate, Long limit, Long offset, OrderSpecifier<?>... orderSpecifiers) { JPAQuery<T> query = queryByPredicate(entityPath, predicate, limit, offset); if (orderSpecifiers != null && orderSpecifiers.length > 0) { query.orderBy(orderSpecifiers); } return query; } protected <T> JPAQuery<T> queryByPredicate(EntityPath<T> entityPath, Predicate predicate) { return queryByPredicate(entityPath, predicate, null, null); } protected <T> JPAQuery<T> queryByPredicate(EntityPath<T> entityPath, Predicate predicate, Long limit, Long offset) { JPAQuery<T> query = new JPAQuery<>(getEntityManager()); query.select(entityPath) .from(entityPath); if (predicate != null) { query.where(predicate); } if (offset != null) { query.offset(offset); } if (limit != null) { query.limit(limit); } return query; } }