Skip to content

Commit b5474bd

Browse files
committed
Consistently document JpaSpecificationExecutor to require non-null Specification.
Closes #2877
1 parent 8d4c40f commit b5474bd

File tree

2 files changed

+63
-61
lines changed

2 files changed

+63
-61
lines changed

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/JpaSpecificationExecutor.java

+18-18
Original file line numberDiff line numberDiff line change
@@ -24,73 +24,73 @@
2424
import org.springframework.data.domain.Sort;
2525
import org.springframework.data.jpa.domain.Specification;
2626
import org.springframework.data.repository.query.FluentQuery;
27-
import org.springframework.lang.Nullable;
2827

2928
/**
3029
* Interface to allow execution of {@link Specification}s based on the JPA criteria API.
3130
*
3231
* @author Oliver Gierke
3332
* @author Christoph Strobl
3433
* @author Diego Krupitza
34+
* @author Mark Paluch
3535
*/
3636
public interface JpaSpecificationExecutor<T> {
3737

3838
/**
3939
* Returns a single entity matching the given {@link Specification} or {@link Optional#empty()} if none found.
4040
*
41-
* @param spec can be {@literal null}.
41+
* @param spec must not be {@literal null}.
4242
* @return never {@literal null}.
4343
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException if more than one entity found.
4444
*/
45-
Optional<T> findOne(@Nullable Specification<T> spec);
45+
Optional<T> findOne(Specification<T> spec);
4646

4747
/**
4848
* Returns all entities matching the given {@link Specification}.
4949
*
50-
* @param spec can be {@literal null}.
50+
* @param spec must not be {@literal null}.
5151
* @return never {@literal null}.
5252
*/
53-
List<T> findAll(@Nullable Specification<T> spec);
53+
List<T> findAll(Specification<T> spec);
5454

5555
/**
5656
* Returns a {@link Page} of entities matching the given {@link Specification}.
5757
*
58-
* @param spec can be {@literal null}.
58+
* @param spec must not be {@literal null}.
5959
* @param pageable must not be {@literal null}.
6060
* @return never {@literal null}.
6161
*/
62-
Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable);
62+
Page<T> findAll(Specification<T> spec, Pageable pageable);
6363

6464
/**
6565
* Returns all entities matching the given {@link Specification} and {@link Sort}.
6666
*
67-
* @param spec can be {@literal null}.
67+
* @param spec must not be {@literal null}.
6868
* @param sort must not be {@literal null}.
6969
* @return never {@literal null}.
7070
*/
71-
List<T> findAll(@Nullable Specification<T> spec, Sort sort);
71+
List<T> findAll(Specification<T> spec, Sort sort);
7272

7373
/**
7474
* Returns the number of instances that the given {@link Specification} will return.
7575
*
76-
* @param spec the {@link Specification} to count instances for. Can be {@literal null}.
76+
* @param spec the {@link Specification} to count instances for, must not be {@literal null}.
7777
* @return the number of instances.
7878
*/
79-
long count(@Nullable Specification<T> spec);
79+
long count(Specification<T> spec);
8080

8181
/**
8282
* Checks whether the data store contains elements that match the given {@link Specification}.
83-
*
84-
* @param spec the {@link Specification} to use for the existence check. Must not be {@literal null}.
85-
* @return <code>true</code> if the data store contains elements that match the given {@link Specification} otherwise
86-
* <code>false</code>.
83+
*
84+
* @param spec the {@link Specification} to use for the existence check, ust not be {@literal null}.
85+
* @return {@code true} if the data store contains elements that match the given {@link Specification} otherwise
86+
* {@code false}.
8787
*/
8888
boolean exists(Specification<T> spec);
8989

9090
/**
9191
* Deletes by the {@link Specification} and returns the number of rows deleted.
9292
*
93-
* @param spec the {@link Specification} to use for the existence check. Must not be {@literal null}.
93+
* @param spec the {@link Specification} to use for the existence check, must not be {@literal null}.
9494
* @return the number of entities deleted
9595
*/
9696
long delete(Specification<T> spec);
@@ -99,8 +99,8 @@ public interface JpaSpecificationExecutor<T> {
9999
* Returns entities matching the given {@link Specification} applying the {@code queryFunction} that defines the query
100100
* and its result type.
101101
*
102-
* @param spec must not be null.
103-
* @param queryFunction the query function defining projection, sorting, and the result type
102+
* @param spec must not be null.
103+
* @param queryFunction the query function defining projection, sorting, and the result type
104104
* @return all entities matching the given Example.
105105
* @since 3.0
106106
*/

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java

+45-43
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ public Page<T> findAll(Pageable pageable) {
447447
}
448448

449449
@Override
450-
public Optional<T> findOne(@Nullable Specification<T> spec) {
450+
public Optional<T> findOne(Specification<T> spec) {
451451

452452
try {
453453
return Optional.of(getQuery(spec, Sort.unsorted()).setMaxResults(2).getSingleResult());
@@ -457,23 +457,64 @@ public Optional<T> findOne(@Nullable Specification<T> spec) {
457457
}
458458

459459
@Override
460-
public List<T> findAll(@Nullable Specification<T> spec) {
460+
public List<T> findAll(Specification<T> spec) {
461461
return getQuery(spec, Sort.unsorted()).getResultList();
462462
}
463463

464464
@Override
465-
public Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable) {
465+
public Page<T> findAll(Specification<T> spec, Pageable pageable) {
466466

467467
TypedQuery<T> query = getQuery(spec, pageable);
468468
return isUnpaged(pageable) ? new PageImpl<>(query.getResultList())
469469
: readPage(query, getDomainClass(), pageable, spec);
470470
}
471471

472472
@Override
473-
public List<T> findAll(@Nullable Specification<T> spec, Sort sort) {
473+
public List<T> findAll(Specification<T> spec, Sort sort) {
474474
return getQuery(spec, sort).getResultList();
475475
}
476476

477+
@Override
478+
public boolean exists(Specification<T> spec) {
479+
480+
CriteriaQuery<Integer> cq = this.em.getCriteriaBuilder().createQuery(Integer.class);
481+
cq.select(this.em.getCriteriaBuilder().literal(1));
482+
applySpecificationToCriteria(spec, getDomainClass(), cq);
483+
TypedQuery<Integer> query = applyRepositoryMethodMetadata(this.em.createQuery(cq));
484+
return query.setMaxResults(1).getResultList().size() == 1;
485+
}
486+
487+
@Override
488+
public long delete(Specification<T> spec) {
489+
490+
CriteriaBuilder builder = this.em.getCriteriaBuilder();
491+
CriteriaDelete<T> delete = builder.createCriteriaDelete(getDomainClass());
492+
493+
if (spec != null) {
494+
Predicate predicate = spec.toPredicate(delete.from(getDomainClass()), null, builder);
495+
496+
if (predicate != null) {
497+
delete.where(predicate);
498+
}
499+
}
500+
501+
return this.em.createQuery(delete).executeUpdate();
502+
}
503+
504+
@Override
505+
public <S extends T, R> R findBy(Specification<T> spec, Function<FetchableFluentQuery<S>, R> queryFunction) {
506+
507+
Assert.notNull(spec, "Specification must not be null");
508+
Assert.notNull(queryFunction, "Query function must not be null");
509+
510+
Function<Sort, TypedQuery<T>> finder = sort -> getQuery(spec, getDomainClass(), sort);
511+
512+
FetchableFluentQuery<R> fluentQuery = new FetchableFluentQueryBySpecification<T, R>(spec, getDomainClass(),
513+
Sort.unsorted(), null, finder, this::count, this::exists, this.em);
514+
515+
return queryFunction.apply((FetchableFluentQuery<S>) fluentQuery);
516+
}
517+
477518
@Override
478519
public <S extends T> Optional<S> findOne(Example<S> example) {
479520

@@ -503,32 +544,6 @@ public <S extends T> boolean exists(Example<S> example) {
503544
return query.setMaxResults(1).getResultList().size() == 1;
504545
}
505546

506-
@Override
507-
public boolean exists(Specification<T> spec) {
508-
509-
CriteriaQuery<Integer> cq = this.em.getCriteriaBuilder().createQuery(Integer.class);
510-
cq.select(this.em.getCriteriaBuilder().literal(1));
511-
applySpecificationToCriteria(spec, getDomainClass(), cq);
512-
TypedQuery<Integer> query = applyRepositoryMethodMetadata(this.em.createQuery(cq));
513-
return query.setMaxResults(1).getResultList().size() == 1;
514-
}
515-
516-
@Override
517-
public long delete(Specification<T> spec) {
518-
519-
CriteriaBuilder builder = this.em.getCriteriaBuilder();
520-
CriteriaDelete<T> delete = builder.createCriteriaDelete(getDomainClass());
521-
522-
if (spec != null) {
523-
Predicate predicate = spec.toPredicate(delete.from(getDomainClass()), null, builder);
524-
525-
if (predicate != null) {
526-
delete.where(predicate);
527-
}
528-
}
529-
530-
return this.em.createQuery(delete).executeUpdate();
531-
}
532547

533548
@Override
534549
public <S extends T> List<S> findAll(Example<S> example) {
@@ -571,19 +586,6 @@ public <S extends T, R> R findBy(Example<S> example, Function<FetchableFluentQue
571586
return queryFunction.apply(fluentQuery);
572587
}
573588

574-
@Override
575-
public <S extends T, R> R findBy(Specification<T> spec, Function<FetchableFluentQuery<S>, R> queryFunction) {
576-
577-
Assert.notNull(spec, "Specification must not be null");
578-
Assert.notNull(queryFunction, "Query function must not be null");
579-
580-
Function<Sort, TypedQuery<T>> finder = sort -> getQuery(spec, getDomainClass(), sort);
581-
582-
FetchableFluentQuery<R> fluentQuery = new FetchableFluentQueryBySpecification<T, R>(spec, getDomainClass(),
583-
Sort.unsorted(), null, finder, this::count, this::exists, this.em);
584-
585-
return queryFunction.apply((FetchableFluentQuery<S>) fluentQuery);
586-
}
587589

588590
@Override
589591
public long count() {

0 commit comments

Comments
 (0)