Skip to content

Commit ad2f85e

Browse files
committed
Polishing.
Revise nullability requirements around non-nullable specifications. Original Pull Request: #3578
1 parent cc1d9bd commit ad2f85e

File tree

4 files changed

+27
-89
lines changed

4 files changed

+27
-89
lines changed

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

+3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
import java.util.Optional;
2626
import java.util.function.Function;
2727

28+
import org.springframework.dao.InvalidDataAccessApiUsageException;
29+
import org.jspecify.annotations.Nullable;
30+
2831
import org.springframework.dao.InvalidDataAccessApiUsageException;
2932
import org.springframework.data.domain.Page;
3033
import org.springframework.data.domain.Pageable;

Diff for: spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryBySpecification.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import java.util.function.Function;
2727
import java.util.stream.Stream;
2828

29+
import org.jspecify.annotations.Nullable;
30+
2931
import org.springframework.dao.IncorrectResultSizeDataAccessException;
3032
import org.springframework.data.domain.Page;
3133
import org.springframework.data.domain.PageImpl;
@@ -174,18 +176,18 @@ public Window<R> scroll(ScrollPosition scrollPosition) {
174176

175177
@Override
176178
public Slice<R> slice(Pageable pageable) {
177-
return pageable.isUnpaged() ? new PageImpl<>(all(pageable.getSortOr(this.sort))) : readSlice(pageable);
179+
return pageable.isUnpaged() ? new PageImpl<>(all(pageable.getSort())) : readSlice(pageable);
178180
}
179181

180182
@Override
181183
public Page<R> page(Pageable pageable) {
182-
return pageable.isUnpaged() ? new PageImpl<>(all(pageable.getSortOr(this.sort))) : readPage(pageable, spec);
184+
return pageable.isUnpaged() ? new PageImpl<>(all(pageable.getSort())) : readPage(pageable, spec);
183185
}
184186

185187
@Override
186188
@SuppressWarnings({ "rawtypes", "unchecked" })
187189
public Page<R> page(Pageable pageable, Specification<?> countSpec) {
188-
return pageable.isUnpaged() ? new PageImpl<>(all(pageable.getSortOr(this.sort)))
190+
return pageable.isUnpaged() ? new PageImpl<>(all(pageable.getSort()))
189191
: readPage(pageable, (Specification) countSpec);
190192
}
191193

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

+19-13
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,7 @@ public <S extends T, R> R findBy(Specification<T> spec,
513513
return doFindBy(spec, getDomainClass(), queryFunction);
514514
}
515515

516+
@SuppressWarnings("unchecked")
516517
private <S extends T, R> R doFindBy(Specification<T> spec, Class<T> domainClass,
517518
Function<? super SpecificationFluentQuery<S>, R> queryFunction) {
518519

@@ -610,6 +611,7 @@ public <S extends T> Page<S> findAll(Example<S> example, Pageable pageable) {
610611
}
611612

612613
@Override
614+
@SuppressWarnings("unchecked")
613615
public <S extends T, R> R findBy(Example<S> example, Function<FetchableFluentQuery<S>, R> queryFunction) {
614616

615617
Assert.notNull(example, EXAMPLE_MUST_NOT_BE_NULL);
@@ -632,7 +634,7 @@ public long count() {
632634
}
633635

634636
@Override
635-
public long count(@Nullable Specification<T> spec) {
637+
public long count(Specification<T> spec) {
636638
return executeCountQuery(getCountQuery(spec, getDomainClass()));
637639
}
638640

@@ -701,7 +703,7 @@ public void flush() {
701703
* @deprecated use {@link #readPage(TypedQuery, Class, Pageable, Specification)} instead
702704
*/
703705
@Deprecated
704-
protected Page<T> readPage(TypedQuery<T> query, Pageable pageable, @Nullable Specification<T> spec) {
706+
protected Page<T> readPage(TypedQuery<T> query, Pageable pageable, Specification<T> spec) {
705707
return readPage(query, getDomainClass(), pageable, spec);
706708
}
707709

@@ -711,11 +713,13 @@ protected Page<T> readPage(TypedQuery<T> query, Pageable pageable, @Nullable Spe
711713
*
712714
* @param query must not be {@literal null}.
713715
* @param domainClass must not be {@literal null}.
714-
* @param spec can be {@literal null}.
716+
* @param spec must not be {@literal null}.
715717
* @param pageable can be {@literal null}.
716718
*/
717719
protected <S extends T> Page<S> readPage(TypedQuery<S> query, Class<S> domainClass, Pageable pageable,
718-
@Nullable Specification<S> spec) {
720+
Specification<S> spec) {
721+
722+
Assert.notNull(spec, "Specification must not be null");
719723

720724
if (pageable.isPaged()) {
721725
query.setFirstResult(PageableUtils.getOffsetAsInteger(pageable));
@@ -729,21 +733,21 @@ protected <S extends T> Page<S> readPage(TypedQuery<S> query, Class<S> domainCla
729733
/**
730734
* Creates a new {@link TypedQuery} from the given {@link Specification}.
731735
*
732-
* @param spec can be {@literal null}.
736+
* @param spec must not be {@literal null}.
733737
* @param pageable must not be {@literal null}.
734738
*/
735-
protected TypedQuery<T> getQuery(@Nullable Specification<T> spec, Pageable pageable) {
739+
protected TypedQuery<T> getQuery(Specification<T> spec, Pageable pageable) {
736740
return getQuery(spec, getDomainClass(), pageable.getSort());
737741
}
738742

739743
/**
740744
* Creates a new {@link TypedQuery} from the given {@link Specification}.
741745
*
742-
* @param spec can be {@literal null}.
746+
* @param spec must not be {@literal null}.
743747
* @param domainClass must not be {@literal null}.
744748
* @param pageable must not be {@literal null}.
745749
*/
746-
protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec, Class<S> domainClass,
750+
protected <S extends T> TypedQuery<S> getQuery(Specification<S> spec, Class<S> domainClass,
747751
Pageable pageable) {
748752
return getQuery(spec, domainClass, pageable.getSort());
749753
}
@@ -877,21 +881,23 @@ protected <S> Query getDelete(DeleteSpecification<S> spec, Class<S> domainClass)
877881
/**
878882
* Creates a new count query for the given {@link Specification}.
879883
*
880-
* @param spec can be {@literal null}.
884+
* @param spec must not be {@literal null}.
881885
* @deprecated override {@link #getCountQuery(Specification, Class)} instead
882886
*/
883887
@Deprecated
884-
protected TypedQuery<Long> getCountQuery(@Nullable Specification<T> spec) {
888+
protected TypedQuery<Long> getCountQuery(Specification<T> spec) {
885889
return getCountQuery(spec, getDomainClass());
886890
}
887891

888892
/**
889893
* Creates a new count query for the given {@link Specification}.
890894
*
891-
* @param spec can be {@literal null}.
895+
* @param spec must not be {@literal null}.
892896
* @param domainClass must not be {@literal null}.
893897
*/
894-
protected <S extends T> TypedQuery<Long> getCountQuery(@Nullable Specification<S> spec, Class<S> domainClass) {
898+
protected <S extends T> TypedQuery<Long> getCountQuery(Specification<S> spec, Class<S> domainClass) {
899+
900+
Assert.notNull(spec, "Specification must not be null");
895901

896902
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
897903
CriteriaQuery<Long> query = builder.createQuery(Long.class);
@@ -1041,7 +1047,7 @@ private Map<String, Object> getHints() {
10411047
private void applyComment(CrudMethodMetadata metadata, BiConsumer<String, Object> consumer) {
10421048

10431049
if (metadata.getComment() != null && provider.getCommentHintKey() != null) {
1044-
consumer.accept(provider.getCommentHintKey(), provider.getCommentHintValue(this.metadata.getComment()));
1050+
consumer.accept(provider.getCommentHintKey(), provider.getCommentHintValue(metadata.getComment()));
10451051
}
10461052
}
10471053

Diff for: spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/SpecificationUnitTests.java

-73
Original file line numberDiff line numberDiff line change
@@ -62,79 +62,6 @@ void setUp() {
6262
spec = (root, query, cb) -> predicate;
6363
}
6464

65-
@Test // DATAJPA-300, DATAJPA-1170
66-
void createsSpecificationsFromNull() {
67-
68-
Specification<Object> specification = where(null);
69-
assertThat(specification).isNotNull();
70-
assertThat(specification.toPredicate(root, query, builder)).isNull();
71-
}
72-
73-
@Test // DATAJPA-300, DATAJPA-1170
74-
void negatesNullSpecToNull() {
75-
76-
Specification<Object> specification = not(null);
77-
78-
assertThat(specification).isNotNull();
79-
assertThat(specification.toPredicate(root, query, builder)).isNull();
80-
}
81-
82-
@Test // DATAJPA-300, DATAJPA-1170
83-
void andConcatenatesSpecToNullSpec() {
84-
85-
Specification<Object> specification = where(null);
86-
specification = specification.and(spec);
87-
88-
assertThat(specification).isNotNull();
89-
assertThat(specification.toPredicate(root, query, builder)).isEqualTo(predicate);
90-
}
91-
92-
@Test // DATAJPA-300, DATAJPA-1170
93-
void andConcatenatesNullSpecToSpec() {
94-
95-
Specification<Object> specification = spec.and(null);
96-
97-
assertThat(specification).isNotNull();
98-
assertThat(specification.toPredicate(root, query, builder)).isEqualTo(predicate);
99-
}
100-
101-
@Test // DATAJPA-300, DATAJPA-1170
102-
void orConcatenatesSpecToNullSpec() {
103-
104-
Specification<Object> specification = where(null);
105-
specification = specification.or(spec);
106-
107-
assertThat(specification).isNotNull();
108-
assertThat(specification.toPredicate(root, query, builder)).isEqualTo(predicate);
109-
}
110-
111-
@Test // DATAJPA-300, DATAJPA-1170
112-
void orConcatenatesNullSpecToSpec() {
113-
114-
Specification<Object> specification = spec.or(null);
115-
116-
assertThat(specification).isNotNull();
117-
assertThat(specification.toPredicate(root, query, builder)).isEqualTo(predicate);
118-
}
119-
120-
@Test // GH-1943
121-
void allOfConcatenatesNull() {
122-
123-
Specification<Object> specification = Specification.allOf(null, spec, null);
124-
125-
assertThat(specification).isNotNull();
126-
assertThat(specification.toPredicate(root, query, builder)).isEqualTo(predicate);
127-
}
128-
129-
@Test // GH-1943
130-
void anyOfConcatenatesNull() {
131-
132-
Specification<Object> specification = Specification.anyOf(null, spec, null);
133-
134-
assertThat(specification).isNotNull();
135-
assertThat(specification.toPredicate(root, query, builder)).isEqualTo(predicate);
136-
}
137-
13865
@Test // GH-1943
13966
void emptyAllOfReturnsEmptySpecification() {
14067

0 commit comments

Comments
 (0)