Consistently document JpaSpecificationExecutor to require non-null Specification.
Closes #2877
This commit is contained in:
@@ -24,7 +24,6 @@ import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.repository.query.FluentQuery;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Interface to allow execution of {@link Specification}s based on the JPA criteria API.
|
||||
@@ -32,65 +31,66 @@ import org.springframework.lang.Nullable;
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Diego Krupitza
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface JpaSpecificationExecutor<T> {
|
||||
|
||||
/**
|
||||
* Returns a single entity matching the given {@link Specification} or {@link Optional#empty()} if none found.
|
||||
*
|
||||
* @param spec can be {@literal null}.
|
||||
* @param spec must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException if more than one entity found.
|
||||
*/
|
||||
Optional<T> findOne(@Nullable Specification<T> spec);
|
||||
Optional<T> findOne(Specification<T> spec);
|
||||
|
||||
/**
|
||||
* Returns all entities matching the given {@link Specification}.
|
||||
*
|
||||
* @param spec can be {@literal null}.
|
||||
* @param spec must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
List<T> findAll(@Nullable Specification<T> spec);
|
||||
List<T> findAll(Specification<T> spec);
|
||||
|
||||
/**
|
||||
* Returns a {@link Page} of entities matching the given {@link Specification}.
|
||||
*
|
||||
* @param spec can be {@literal null}.
|
||||
* @param spec must not be {@literal null}.
|
||||
* @param pageable must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable);
|
||||
Page<T> findAll(Specification<T> spec, Pageable pageable);
|
||||
|
||||
/**
|
||||
* Returns all entities matching the given {@link Specification} and {@link Sort}.
|
||||
*
|
||||
* @param spec can be {@literal null}.
|
||||
* @param spec must not be {@literal null}.
|
||||
* @param sort must not be {@literal null}.
|
||||
* @return never {@literal null}.
|
||||
*/
|
||||
List<T> findAll(@Nullable Specification<T> spec, Sort sort);
|
||||
List<T> findAll(Specification<T> spec, Sort sort);
|
||||
|
||||
/**
|
||||
* Returns the number of instances that the given {@link Specification} will return.
|
||||
*
|
||||
* @param spec the {@link Specification} to count instances for. Can be {@literal null}.
|
||||
* @param spec the {@link Specification} to count instances for, must not be {@literal null}.
|
||||
* @return the number of instances.
|
||||
*/
|
||||
long count(@Nullable Specification<T> spec);
|
||||
long count(Specification<T> spec);
|
||||
|
||||
/**
|
||||
* Checks whether the data store contains elements that match the given {@link Specification}.
|
||||
*
|
||||
* @param spec the {@link Specification} to use for the existence check. Must not be {@literal null}.
|
||||
* @return <code>true</code> if the data store contains elements that match the given {@link Specification} otherwise
|
||||
* <code>false</code>.
|
||||
*
|
||||
* @param spec the {@link Specification} to use for the existence check, ust not be {@literal null}.
|
||||
* @return {@code true} if the data store contains elements that match the given {@link Specification} otherwise
|
||||
* {@code false}.
|
||||
*/
|
||||
boolean exists(Specification<T> spec);
|
||||
|
||||
/**
|
||||
* Deletes by the {@link Specification} and returns the number of rows deleted.
|
||||
*
|
||||
* @param spec the {@link Specification} to use for the existence check. Must not be {@literal null}.
|
||||
* @param spec the {@link Specification} to use for the existence check, must not be {@literal null}.
|
||||
* @return the number of entities deleted
|
||||
*/
|
||||
long delete(Specification<T> spec);
|
||||
@@ -99,8 +99,8 @@ public interface JpaSpecificationExecutor<T> {
|
||||
* Returns entities matching the given {@link Specification} applying the {@code queryFunction} that defines the query
|
||||
* and its result type.
|
||||
*
|
||||
* @param spec – must not be null.
|
||||
* @param queryFunction – the query function defining projection, sorting, and the result type
|
||||
* @param spec must not be null.
|
||||
* @param queryFunction the query function defining projection, sorting, and the result type
|
||||
* @return all entities matching the given Example.
|
||||
* @since 3.0
|
||||
*/
|
||||
|
||||
@@ -447,7 +447,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<T> findOne(@Nullable Specification<T> spec) {
|
||||
public Optional<T> findOne(Specification<T> spec) {
|
||||
|
||||
try {
|
||||
return Optional.of(getQuery(spec, Sort.unsorted()).setMaxResults(2).getSingleResult());
|
||||
@@ -457,12 +457,12 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> findAll(@Nullable Specification<T> spec) {
|
||||
public List<T> findAll(Specification<T> spec) {
|
||||
return getQuery(spec, Sort.unsorted()).getResultList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable) {
|
||||
public Page<T> findAll(Specification<T> spec, Pageable pageable) {
|
||||
|
||||
TypedQuery<T> query = getQuery(spec, pageable);
|
||||
return isUnpaged(pageable) ? new PageImpl<>(query.getResultList())
|
||||
@@ -470,10 +470,51 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> findAll(@Nullable Specification<T> spec, Sort sort) {
|
||||
public List<T> findAll(Specification<T> spec, Sort sort) {
|
||||
return getQuery(spec, sort).getResultList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(Specification<T> spec) {
|
||||
|
||||
CriteriaQuery<Integer> cq = this.em.getCriteriaBuilder().createQuery(Integer.class);
|
||||
cq.select(this.em.getCriteriaBuilder().literal(1));
|
||||
applySpecificationToCriteria(spec, getDomainClass(), cq);
|
||||
TypedQuery<Integer> query = applyRepositoryMethodMetadata(this.em.createQuery(cq));
|
||||
return query.setMaxResults(1).getResultList().size() == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long delete(Specification<T> spec) {
|
||||
|
||||
CriteriaBuilder builder = this.em.getCriteriaBuilder();
|
||||
CriteriaDelete<T> delete = builder.createCriteriaDelete(getDomainClass());
|
||||
|
||||
if (spec != null) {
|
||||
Predicate predicate = spec.toPredicate(delete.from(getDomainClass()), null, builder);
|
||||
|
||||
if (predicate != null) {
|
||||
delete.where(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
return this.em.createQuery(delete).executeUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends T, R> R findBy(Specification<T> spec, Function<FetchableFluentQuery<S>, R> queryFunction) {
|
||||
|
||||
Assert.notNull(spec, "Specification must not be null");
|
||||
Assert.notNull(queryFunction, "Query function must not be null");
|
||||
|
||||
Function<Sort, TypedQuery<T>> finder = sort -> getQuery(spec, getDomainClass(), sort);
|
||||
|
||||
FetchableFluentQuery<R> fluentQuery = new FetchableFluentQueryBySpecification<T, R>(spec, getDomainClass(),
|
||||
Sort.unsorted(), null, finder, this::count, this::exists, this.em);
|
||||
|
||||
return queryFunction.apply((FetchableFluentQuery<S>) fluentQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends T> Optional<S> findOne(Example<S> example) {
|
||||
|
||||
@@ -503,32 +544,6 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
||||
return query.setMaxResults(1).getResultList().size() == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(Specification<T> spec) {
|
||||
|
||||
CriteriaQuery<Integer> cq = this.em.getCriteriaBuilder().createQuery(Integer.class);
|
||||
cq.select(this.em.getCriteriaBuilder().literal(1));
|
||||
applySpecificationToCriteria(spec, getDomainClass(), cq);
|
||||
TypedQuery<Integer> query = applyRepositoryMethodMetadata(this.em.createQuery(cq));
|
||||
return query.setMaxResults(1).getResultList().size() == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long delete(Specification<T> spec) {
|
||||
|
||||
CriteriaBuilder builder = this.em.getCriteriaBuilder();
|
||||
CriteriaDelete<T> delete = builder.createCriteriaDelete(getDomainClass());
|
||||
|
||||
if (spec != null) {
|
||||
Predicate predicate = spec.toPredicate(delete.from(getDomainClass()), null, builder);
|
||||
|
||||
if (predicate != null) {
|
||||
delete.where(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
return this.em.createQuery(delete).executeUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends T> List<S> findAll(Example<S> example) {
|
||||
@@ -571,19 +586,6 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
||||
return queryFunction.apply(fluentQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends T, R> R findBy(Specification<T> spec, Function<FetchableFluentQuery<S>, R> queryFunction) {
|
||||
|
||||
Assert.notNull(spec, "Specification must not be null");
|
||||
Assert.notNull(queryFunction, "Query function must not be null");
|
||||
|
||||
Function<Sort, TypedQuery<T>> finder = sort -> getQuery(spec, getDomainClass(), sort);
|
||||
|
||||
FetchableFluentQuery<R> fluentQuery = new FetchableFluentQueryBySpecification<T, R>(spec, getDomainClass(),
|
||||
Sort.unsorted(), null, finder, this::count, this::exists, this.em);
|
||||
|
||||
return queryFunction.apply((FetchableFluentQuery<S>) fluentQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
|
||||
Reference in New Issue
Block a user