Update nullability annotations and javadoc.

Reflect allowed null arguments in both documentation as well as supporting annotations.
Going forward we should consider if there is a possibility to restructure Specification and the Predicate handling to avoid this at all (#3521).

See: #3036
This commit is contained in:
Christoph Strobl
2024-06-20 13:24:45 +02:00
parent 206c4f55e3
commit d60efe6cf9
4 changed files with 27 additions and 16 deletions

View File

@@ -96,12 +96,12 @@ public interface Specification<T> extends Serializable {
* {@link Root} and {@link CriteriaQuery}.
*
* @param root must not be {@literal null}.
* @param query must not be {@literal null}.
* @param query can be {@literal null} to allow overrides that accept {@link jakarta.persistence.criteria.CriteriaDelete} which is an {@link jakarta.persistence.criteria.AbstractQuery} but no {@link CriteriaQuery}.
* @param criteriaBuilder must not be {@literal null}.
* @return a {@link Predicate}, may be {@literal null}.
*/
@Nullable
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);
Predicate toPredicate(Root<T> root, @Nullable CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);
/**
* Applies an AND operation to all the given {@link Specification}s.

View File

@@ -57,7 +57,7 @@ class SpecificationComposition {
}
@Nullable
private static <T> Predicate toPredicate(@Nullable Specification<T> specification, Root<T> root, CriteriaQuery<?> query,
private static <T> Predicate toPredicate(@Nullable Specification<T> specification, Root<T> root, @Nullable CriteriaQuery<?> query,
CriteriaBuilder builder) {
return specification == null ? null : specification.toPredicate(root, query, builder);
}

View File

@@ -28,6 +28,7 @@ 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.
@@ -50,37 +51,45 @@ public interface JpaSpecificationExecutor<T> {
/**
* Returns all entities matching the given {@link Specification}.
* <p>
* If no {@link Specification} is given all entities matching {@code <T>} will be selected.
*
* @param spec must not be {@literal null}.
* @param spec can be {@literal null}.
* @return never {@literal null}.
*/
List<T> findAll(Specification<T> spec);
List<T> findAll(@Nullable Specification<T> spec);
/**
* Returns a {@link Page} of entities matching the given {@link Specification}.
* <p>
* If no {@link Specification} is given all entities matching {@code <T>} will be selected.
*
* @param spec must not be {@literal null}.
* @param spec can be {@literal null}.
* @param pageable must not be {@literal null}.
* @return never {@literal null}.
*/
Page<T> findAll(Specification<T> spec, Pageable pageable);
Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable);
/**
* Returns all entities matching the given {@link Specification} and {@link Sort}.
* <p>
* If no {@link Specification} is given all entities matching {@code <T>} will be selected.
*
* @param spec must not be {@literal null}.
* @param spec can be {@literal null}.
* @param sort must not be {@literal null}.
* @return never {@literal null}.
*/
List<T> findAll(Specification<T> spec, Sort sort);
List<T> findAll(@Nullable Specification<T> spec, Sort sort);
/**
* Returns the number of instances that the given {@link Specification} will return.
* <p>
* If no {@link Specification} is given all entities matching {@code <T>} will be counted.
*
* @param spec the {@link Specification} to count instances for, must not be {@literal null}.
* @return the number of instances.
*/
long count(Specification<T> spec);
long count(@Nullable Specification<T> spec);
/**
* Checks whether the data store contains elements that match the given {@link Specification}.
@@ -101,12 +110,14 @@ public interface JpaSpecificationExecutor<T> {
* {@link Specification#toPredicate(Root, CriteriaQuery, CriteriaBuilder)} will be {@literal null} because
* {@link jakarta.persistence.criteria.CriteriaBuilder#createCriteriaDelete(Class)} does not implement
* {@code CriteriaQuery}.
* <p>
* If no {@link Specification} is given all entities matching {@code <T>} will be 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, can not be {@literal null}.
* @return the number of entities deleted.
* @since 3.0
*/
long delete(Specification<T> spec);
long delete(@Nullable Specification<T> spec);
/**
* Returns entities matching the given {@link Specification} applying the {@code queryFunction} that defines the query

View File

@@ -431,7 +431,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
return new PageImpl<>(findAll());
}
return findAll((root, query, criteriaBuilder) -> null, pageable);
return findAll((Specification<T>) null, pageable);
}
@Override
@@ -450,7 +450,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
}
@Override
public Page<T> findAll(Specification<T> spec, Pageable pageable) {
public Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable) {
TypedQuery<T> query = getQuery(spec, pageable);
return pageable.isUnpaged() ? new PageImpl<>(query.getResultList())
@@ -458,7 +458,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
}
@Override
public List<T> findAll(Specification<T> spec, Sort sort) {
public List<T> findAll(@Nullable Specification<T> spec, Sort sort) {
return getQuery(spec, sort).getResultList();
}
@@ -477,7 +477,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
@Override
@Transactional
public long delete(Specification<T> spec) {
public long delete(@Nullable Specification<T> spec) {
CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
CriteriaDelete<T> delete = builder.createCriteriaDelete(getDomainClass());