Java tutorial
package com.uni.dao.etc; /* * Copyright 2008-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import static org.springframework.data.jpa.repository.query.QueryUtils.COUNT_QUERY_STRING; import static org.springframework.data.jpa.repository.query.QueryUtils.DELETE_ALL_QUERY_STRING; import static org.springframework.data.jpa.repository.query.QueryUtils.EXISTS_QUERY_STRING; import static org.springframework.data.jpa.repository.query.QueryUtils.applyAndBind; import static org.springframework.data.jpa.repository.query.QueryUtils.getQueryString; import static org.springframework.data.jpa.repository.query.QueryUtils.toOrders; import static org.springframework.data.jpa.repository.utils.JpaClassUtils.isEntityManagerOfType; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.LockModeType; import javax.persistence.NoResultException; import javax.persistence.NonUniqueResultException; import javax.persistence.Query; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import org.hibernate.ejb.HibernateQuery; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.query.QueryExtractor; import org.springframework.data.jpa.repository.query.QueryUtils; import org.springframework.data.jpa.repository.support.JpaEntityInformation; import org.springframework.data.jpa.repository.support.JpaEntityInformationSupport; import org.springframework.data.jpa.repository.support.LockMetadataProvider; import org.springframework.util.Assert; /** * Default implementation of the {@link org.springframework.data.repository.CrudRepository} interface. This will offer * you a more sophisticated interface than the plain {@link EntityManager} . * * @author Oliver Gierke * @author Eberhard Wolff * @param <T> the type of the entity to handle * @param <ID> the type of the entity's identifier */ public class UniJpaRepository<T, ID extends Serializable> implements JpaRepository<T, ID>, JpaSpecificationExecutor<T> { private final JpaEntityInformation<T, ?> entityInformation; protected final EntityManager em; private final PersistenceProvider provider; private LockMetadataProvider lockMetadataProvider; /** * Creates a new {@link UniJpaRepository} to manage objects of the given {@link JpaEntityInformation}. * * @param entityInformation must not be {@literal null}. * @param entityManager must not be {@literal null}. */ public UniJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) { Assert.notNull(entityInformation); Assert.notNull(entityManager); this.entityInformation = entityInformation; this.em = entityManager; this.provider = PersistenceProvider.fromEntityManager(entityManager); } /** * Creates a new {@link UniJpaRepository} to manage objects of the given domain type. * * @param domainClass must not be {@literal null}. * @param em must not be {@literal null}. */ public UniJpaRepository(Class<T> domainClass, EntityManager em) { this(JpaEntityInformationSupport.getMetadata(domainClass, em), em); } /** * Configures a custom {@link LockMetadataProvider} to be used to detect {@link LockModeType}s to be applied to * queries. * * @param lockMetadataProvider */ public void setLockMetadataProvider(LockMetadataProvider lockMetadataProvider) { this.lockMetadataProvider = lockMetadataProvider; } private Class<T> getDomainClass() { return entityInformation.getJavaType(); } private String getDeleteAllQueryString() { return getQueryString(DELETE_ALL_QUERY_STRING, entityInformation.getEntityName()); } private String getCountQueryString() { String countQuery = String.format(COUNT_QUERY_STRING, provider.getCountQueryPlaceholder(), "%s"); return getQueryString(countQuery, entityInformation.getEntityName()); } /* * (non-Javadoc) * @see org.springframework.data.repository.CrudRepository#delete(java.io.Serializable) */ public void delete(ID id) { Assert.notNull(id, "The given id must not be null!"); if (!exists(id)) { throw new EmptyResultDataAccessException( String.format("No %s entity with id %s exists!", entityInformation.getJavaType(), id), 1); } delete(findOne(id)); } /* * (non-Javadoc) * @see org.springframework.data.repository.CrudRepository#delete(java.lang.Object) */ public void delete(T entity) { Assert.notNull(entity, "The entity must not be null!"); em.remove(em.contains(entity) ? entity : em.merge(entity)); } /* * (non-Javadoc) * @see org.springframework.data.repository.CrudRepository#delete(java.lang.Iterable) */ public void delete(Iterable<? extends T> entities) { Assert.notNull(entities, "The given Iterable of entities not be null!"); for (T entity : entities) { delete(entity); } } /* * (non-Javadoc) * @see org.springframework.data.jpa.repository.JpaRepository#deleteInBatch(java.lang.Iterable) */ public void deleteInBatch(Iterable<T> entities) { Assert.notNull(entities, "The given Iterable of entities not be null!"); if (!entities.iterator().hasNext()) { return; } applyAndBind(getQueryString(DELETE_ALL_QUERY_STRING, entityInformation.getEntityName()), entities, em) .executeUpdate(); } /* * (non-Javadoc) * @see org.springframework.data.repository.Repository#deleteAll() */ public void deleteAll() { for (T element : findAll()) { delete(element); } } /* * (non-Javadoc) * @see org.springframework.data.jpa.repository.JpaRepository#deleteAllInBatch() */ public void deleteAllInBatch() { em.createQuery(getDeleteAllQueryString()).executeUpdate(); } /* * (non-Javadoc) * * @see * org.springframework.data.repository.Repository#readById(java.io.Serializable * ) */ public T findOne(ID id) { Assert.notNull(id, "The given id must not be null!"); return em.find(getDomainClass(), id); } /* * (non-Javadoc) * @see org.springframework.data.repository.CrudRepository#exists(java.io.Serializable) */ public boolean exists(ID id) { Assert.notNull(id, "The given id must not be null!"); if (entityInformation.getIdAttribute() != null) { String placeholder = provider.getCountQueryPlaceholder(); String entityName = entityInformation.getEntityName(); String idAttributeName = entityInformation.getIdAttribute().getName(); String existsQuery = String.format(EXISTS_QUERY_STRING, placeholder, entityName, idAttributeName); TypedQuery<Long> query = em.createQuery(existsQuery, Long.class); query.setParameter("id", id); return query.getSingleResult() == 1; } else { return findOne(id) != null; } } /* * (non-Javadoc) * @see org.springframework.data.jpa.repository.JpaRepository#findAll() */ public List<T> findAll() { return getQuery(null, (Sort) null).getResultList(); } /* * (non-Javadoc) * @see org.springframework.data.repository.CrudRepository#findAll(ID[]) */ public List<T> findAll(Iterable<ID> ids) { return getQuery(new Specification<T>() { public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) { Path<?> path = root.get(entityInformation.getIdAttribute()); return path.in(cb.parameter(Iterable.class, "ids")); } }, (Sort) null).setParameter("ids", ids).getResultList(); } /* * (non-Javadoc) * @see org.springframework.data.jpa.repository.JpaRepository#findAll(org.springframework.data.domain.Sort) */ public List<T> findAll(Sort sort) { return getQuery(null, sort).getResultList(); } /* * (non-Javadoc) * @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Pageable) */ public Page<T> findAll(Pageable pageable) { if (null == pageable) { return new PageImpl<T>(findAll()); } return findAll(null, pageable); } /* * (non-Javadoc) * @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#findOne(org.springframework.data.jpa.domain.Specification) */ public T findOne(Specification<T> spec) { try { return getQuery(spec, (Sort) null).getSingleResult(); } catch (NoResultException e) { return null; } } /* * (non-Javadoc) * @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#findAll(org.springframework.data.jpa.domain.Specification) */ public List<T> findAll(Specification<T> spec) { return getQuery(spec, (Sort) null).getResultList(); } /* * (non-Javadoc) * @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#findAll(org.springframework.data.jpa.domain.Specification, org.springframework.data.domain.Pageable) */ public Page<T> findAll(Specification<T> spec, Pageable pageable) { TypedQuery<T> query = getQuery(spec, pageable); return pageable == null ? new PageImpl<T>(query.getResultList()) : readPage(query, pageable, spec); } /* * (non-Javadoc) * @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#findAll(org.springframework.data.jpa.domain.Specification, org.springframework.data.domain.Sort) */ public List<T> findAll(Specification<T> spec, Sort sort) { return getQuery(spec, sort).getResultList(); } /* * (non-Javadoc) * @see org.springframework.data.repository.CrudRepository#count() */ public long count() { return em.createQuery(getCountQueryString(), Long.class).getSingleResult(); } /* * (non-Javadoc) * @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#count(org.springframework.data.jpa.domain.Specification) */ public long count(Specification<T> spec) { return getCountQuery(spec).getSingleResult(); } /* * (non-Javadoc) * @see org.springframework.data.repository.CrudRepository#save(java.lang.Object) */ public <S extends T> S save(S entity) { if (entityInformation.isNew(entity)) { em.persist(entity); return entity; } else { return em.merge(entity); } } /* * (non-Javadoc) * @see org.springframework.data.jpa.repository.JpaRepository#saveAndFlush(java.lang.Object) */ public T saveAndFlush(T entity) { T result = save(entity); flush(); return result; } /* * (non-Javadoc) * @see org.springframework.data.jpa.repository.JpaRepository#save(java.lang.Iterable) */ public <S extends T> List<S> save(Iterable<S> entities) { List<S> result = new ArrayList<S>(); if (entities == null) { return result; } for (S entity : entities) { result.add(save(entity)); } return result; } /* * (non-Javadoc) * @see org.springframework.data.jpa.repository.JpaRepository#flush() */ public void flush() { em.flush(); } public T findOneBy(String fieldName, String fieldValue) { String stringQuery = "SELECT u FROM " + getDomainClass().getCanonicalName() + " u " + "WHERE u." + fieldName + " = ?1"; System.out.println(stringQuery); TypedQuery<T> query = em.createQuery(stringQuery, getDomainClass()); query.setParameter(1, fieldValue); try { return query.getSingleResult(); } catch (NoResultException e) { return null; } catch (NonUniqueResultException e) { return null; } } /** * Reads the given {@link TypedQuery} into a {@link Page} applying the given {@link Pageable} and * {@link Specification}. * * @param query must not be {@literal null}. * @param spec can be {@literal null}. * @param pageable can be {@literal null}. * @return */ private Page<T> readPage(TypedQuery<T> query, Pageable pageable, Specification<T> spec) { query.setFirstResult(pageable.getOffset()); query.setMaxResults(pageable.getPageSize()); Long total = QueryUtils.executeCountQuery(getCountQuery(spec)); List<T> content = total > pageable.getOffset() ? query.getResultList() : Collections.<T>emptyList(); return new PageImpl<T>(content, pageable, total); } /** * Creates a new {@link TypedQuery} from the given {@link Specification}. * * @param spec can be {@literal null}. * @param pageable can be {@literal null}. * @return */ private TypedQuery<T> getQuery(Specification<T> spec, Pageable pageable) { Sort sort = pageable == null ? null : pageable.getSort(); return getQuery(spec, sort); } /** * Creates a {@link TypedQuery} for the given {@link Specification} and {@link Sort}. * * @param spec can be {@literal null}. * @param sort can be {@literal null}. * @return */ private TypedQuery<T> getQuery(Specification<T> spec, Sort sort) { CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<T> query = builder.createQuery(getDomainClass()); Root<T> root = applySpecificationToCriteria(spec, query); query.select(root); if (sort != null) { query.orderBy(toOrders(sort, root, builder)); } return applyLockMode(em.createQuery(query)); } /** * Creates a new count query for the given {@link Specification}. * * @param spec can be {@literal null}. * @return */ private TypedQuery<Long> getCountQuery(Specification<T> spec) { CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<Long> query = builder.createQuery(Long.class); Root<T> root = applySpecificationToCriteria(spec, query); query.select(builder.count(root)); return em.createQuery(query); } /** * Applies the given {@link Specification} to the given {@link CriteriaQuery}. * * @param spec can be {@literal null}. * @param query must not be {@literal null}. * @return */ private <S> Root<T> applySpecificationToCriteria(Specification<T> spec, CriteriaQuery<S> query) { Assert.notNull(query); Root<T> root = query.from(getDomainClass()); if (spec == null) { return root; } CriteriaBuilder builder = em.getCriteriaBuilder(); Predicate predicate = spec.toPredicate(root, query, builder); if (predicate != null) { query.where(predicate); } return root; } private TypedQuery<T> applyLockMode(TypedQuery<T> query) { LockModeType type = lockMetadataProvider == null ? null : lockMetadataProvider.getLockModeType(); return type == null ? query : query.setLockMode(type); } /* * NESTED */ public enum PersistenceProvider implements QueryExtractor { /** * Hibernate persistence provider. */ HIBERNATE("org.hibernate.ejb.HibernateEntityManager") { public String extractQueryString(Query query) { return ((HibernateQuery) query).getHibernateQuery().getQueryString(); } /** * Return custom placeholder ({@code *}) as Hibernate does create invalid queries for count queries for objects with * compound keys. * * @see HHH-4044 * @see HHH-3096 */ @Override protected String getCountQueryPlaceholder() { return "*"; } }, // /** // * EclipseLink persistence provider. // */ // ECLIPSELINK("org.eclipse.persistence.jpa.JpaEntityManager") { // // public String extractQueryString(Query query) { // // return ((JpaQuery<?>) query).getDatabaseQuery().getJPQLString(); // } // // }, // // /** // * OpenJpa persistence provider. // */ // OPEN_JPA("org.apache.openjpa.persistence.OpenJPAEntityManager") { // // public String extractQueryString(Query query) { // // return ((OpenJPAQuery<?>) query).getQueryString(); // } // }, /** * Unknown special provider. Use standard JPA. */ GENERIC_JPA("javax.persistence.EntityManager") { public String extractQueryString(Query query) { return null; } @Override public boolean canExtractQuery() { return false; } }; private String entityManagerClassName; /** * Creates a new {@link PersistenceProvider}. * * @param entityManagerClassName the name of the provider specific {@link EntityManager} implementation */ private PersistenceProvider(String entityManagerClassName) { this.entityManagerClassName = entityManagerClassName; } /** * Determines the {@link PersistenceProvider} from the given {@link EntityManager}. If no special one can be * determined {@value #GENERIC_JPA} will be returned. * * @param em must not be {@literal null}. * @return will never be {@literal null}. */ public static PersistenceProvider fromEntityManager(EntityManager em) { Assert.notNull(em); for (PersistenceProvider provider : values()) { if (isEntityManagerOfType(em, provider.entityManagerClassName)) { return provider; } } return GENERIC_JPA; } /* * (non-Javadoc) * * @see * org.springframework.data.jpa.repository.query.QueryExtractor#canExtractQuery * () */ public boolean canExtractQuery() { return true; } /** * Returns the placeholder to be used for simple count queries. Default implementation returns {@code *}. * * @return */ protected String getCountQueryPlaceholder() { return "x"; } } }