Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public static <T> Predicate getPredicate(Root<T> root, CriteriaBuilder cb, Examp
* @return {@literal null} indicates no constraints
*/
@Nullable
public static <T> Predicate getPredicate(Root<T> root, CriteriaBuilder cb, Example<T> example,
public static <T> Predicate getPredicate(Root<? extends T> root, CriteriaBuilder cb, Example<T> example,
EscapeCharacter escapeCharacter) {

Assert.notNull(root, "Root must not be null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package org.springframework.data.jpa.domain;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
Expand Down Expand Up @@ -77,7 +76,7 @@ static <T> Specification<T> where(@Nullable Specification<T> spec) {
* @return The conjunction of the specifications
* @since 2.0
*/
default Specification<T> and(@Nullable Specification<T> other) {
default <U extends T> Specification<U> and(@Nullable Specification<? super U> other) {
return SpecificationComposition.composed(this, other, CriteriaBuilder::and);
}

Expand All @@ -88,7 +87,7 @@ default Specification<T> and(@Nullable Specification<T> other) {
* @return The disjunction of the specifications
* @since 2.0
*/
default Specification<T> or(@Nullable Specification<T> other) {
default <U extends T> Specification<U> or(@Nullable Specification<? super U> other) {
return SpecificationComposition.composed(this, other, CriteriaBuilder::or);
}

Expand All @@ -102,7 +101,7 @@ default Specification<T> or(@Nullable Specification<T> other) {
* @return a {@link Predicate}, may be {@literal null}.
*/
@Nullable
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);
Predicate toPredicate(Root<? extends T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);

/**
* Applies an AND operation to all the given {@link Specification}s.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
*/
package org.springframework.data.jpa.domain;

import java.io.Serializable;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;

import java.io.Serializable;

import org.springframework.lang.Nullable;

/**
Expand All @@ -40,7 +40,7 @@ interface Combiner extends Serializable {
Predicate combine(CriteriaBuilder builder, @Nullable Predicate lhs, @Nullable Predicate rhs);
}

static <T> Specification<T> composed(@Nullable Specification<T> lhs, @Nullable Specification<T> rhs,
static <T> Specification<T> composed(@Nullable Specification<? super T> lhs, @Nullable Specification<? super T> rhs,
Combiner combiner) {

return (root, query, builder) -> {
Expand All @@ -57,8 +57,8 @@ static <T> Specification<T> composed(@Nullable Specification<T> lhs, @Nullable S
}

@Nullable
private static <T> Predicate toPredicate(@Nullable Specification<T> specification, Root<T> root, CriteriaQuery<?> query,
CriteriaBuilder builder) {
private static <T> Predicate toPredicate(@Nullable Specification<? super T> specification, Root<? extends T> root,
CriteriaQuery<?> query, CriteriaBuilder builder) {
return specification == null ? null : specification.toPredicate(root, query, builder);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ public interface JpaSpecificationExecutor<T> {
* @return never {@literal null}.
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException if more than one entity found.
*/
Optional<T> findOne(Specification<T> spec);
Optional<T> findOne(Specification<? super T> spec);

/**
* Returns all entities matching the given {@link Specification}.
*
* @param spec must not be {@literal null}.
* @return never {@literal null}.
*/
List<T> findAll(Specification<T> spec);
List<T> findAll(Specification<? super T> spec);

/**
* Returns a {@link Page} of entities matching the given {@link Specification}.
Expand All @@ -63,7 +63,7 @@ public interface JpaSpecificationExecutor<T> {
* @param pageable must not be {@literal null}.
* @return never {@literal null}.
*/
Page<T> findAll(Specification<T> spec, Pageable pageable);
Page<T> findAll(Specification<? super T> spec, Pageable pageable);

/**
* Returns all entities matching the given {@link Specification} and {@link Sort}.
Expand All @@ -72,15 +72,15 @@ public interface JpaSpecificationExecutor<T> {
* @param sort must not be {@literal null}.
* @return never {@literal null}.
*/
List<T> findAll(Specification<T> spec, Sort sort);
List<T> findAll(Specification<? super 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, must not be {@literal null}.
* @return the number of instances.
*/
long count(Specification<T> spec);
long count(Specification<? super T> spec);

/**
* Checks whether the data store contains elements that match the given {@link Specification}.
Expand All @@ -89,7 +89,7 @@ public interface JpaSpecificationExecutor<T> {
* @return {@code true} if the data store contains elements that match the given {@link Specification} otherwise
* {@code false}.
*/
boolean exists(Specification<T> spec);
boolean exists(Specification<? super T> spec);

/**
* Deletes by the {@link Specification} and returns the number of rows deleted.
Expand All @@ -106,7 +106,7 @@ public interface JpaSpecificationExecutor<T> {
* @return the number of entities deleted.
* @since 3.0
*/
long delete(Specification<T> spec);
long delete(Specification<? super T> spec);

/**
* Returns entities matching the given {@link Specification} applying the {@code queryFunction} that defines the query
Expand All @@ -117,6 +117,7 @@ public interface JpaSpecificationExecutor<T> {
* @return all entities matching the given Example.
* @since 3.0
*/
<S extends T, R> R findBy(Specification<T> spec, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction);
<S extends T, R> R findBy(Specification<? super T> spec,
Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction);

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
* @author Christoph Strobl
* @since 3.1
*/
public record KeysetScrollSpecification<T> (KeysetScrollPosition position, Sort sort,
public record KeysetScrollSpecification<T>(KeysetScrollPosition position, Sort sort,
JpaEntityInformation<?, ?> entity) implements Specification<T> {

public KeysetScrollSpecification(KeysetScrollPosition position, Sort sort, JpaEntityInformation<?, ?> entity) {
Expand Down Expand Up @@ -84,7 +84,7 @@ public static Sort createSort(KeysetScrollPosition position, Sort sort, JpaEntit
}

@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
public Predicate toPredicate(Root<? extends T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
return createPredicate(root, criteriaBuilder);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,25 +52,25 @@
class FetchableFluentQueryBySpecification<S, R> extends FluentQuerySupport<S, R>
implements FluentQuery.FetchableFluentQuery<R> {

private final Specification<S> spec;
private final Specification<? super S> spec;
private final Function<Sort, TypedQuery<S>> finder;
private final SpecificationScrollDelegate<S> scroll;
private final Function<Specification<S>, Long> countOperation;
private final Function<Specification<S>, Boolean> existsOperation;
private final Function<Specification<? super S>, Long> countOperation;
private final Function<Specification<? super S>, Boolean> existsOperation;
private final EntityManager entityManager;

public FetchableFluentQueryBySpecification(Specification<S> spec, Class<S> entityType,
public FetchableFluentQueryBySpecification(Specification<? super S> spec, Class<S> entityType,
Function<Sort, TypedQuery<S>> finder, SpecificationScrollDelegate<S> scrollDelegate,
Function<Specification<S>, Long> countOperation, Function<Specification<S>, Boolean> existsOperation,
EntityManager entityManager) {
Function<Specification<? super S>, Long> countOperation,
Function<Specification<? super S>, Boolean> existsOperation, EntityManager entityManager) {
this(spec, entityType, (Class<R>) entityType, Sort.unsorted(), 0, Collections.emptySet(), finder, scrollDelegate,
countOperation, existsOperation, entityManager);
}

private FetchableFluentQueryBySpecification(Specification<S> spec, Class<S> entityType, Class<R> resultType,
private FetchableFluentQueryBySpecification(Specification<? super S> spec, Class<S> entityType, Class<R> resultType,
Sort sort, int limit, Collection<String> properties, Function<Sort, TypedQuery<S>> finder,
SpecificationScrollDelegate<S> scrollDelegate, Function<Specification<S>, Long> countOperation,
Function<Specification<S>, Boolean> existsOperation, EntityManager entityManager) {
SpecificationScrollDelegate<S> scrollDelegate, Function<Specification<? super S>, Long> countOperation,
Function<Specification<? super S>, Boolean> existsOperation, EntityManager entityManager) {

super(resultType, sort, limit, properties, entityType);
this.spec = spec;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ public Page<T> findAll(Pageable pageable) {
}

@Override
public Optional<T> findOne(Specification<T> spec) {
public Optional<T> findOne(Specification<? super T> spec) {

try {
return Optional.of(getQuery(spec, Sort.unsorted()).setMaxResults(2).getSingleResult());
Expand All @@ -437,25 +437,25 @@ public Optional<T> findOne(Specification<T> spec) {
}

@Override
public List<T> findAll(Specification<T> spec) {
public List<T> findAll(Specification<? super T> spec) {
return getQuery(spec, Sort.unsorted()).getResultList();
}

@Override
public Page<T> findAll(Specification<T> spec, Pageable pageable) {
public Page<T> findAll(Specification<? super T> spec, Pageable pageable) {

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

@Override
public List<T> findAll(Specification<T> spec, Sort sort) {
public List<T> findAll(Specification<? super T> spec, Sort sort) {
return getQuery(spec, sort).getResultList();
}

@Override
public boolean exists(Specification<T> spec) {
public boolean exists(Specification<? super T> spec) {

CriteriaQuery<Integer> cq = this.entityManager.getCriteriaBuilder() //
.createQuery(Integer.class) //
Expand All @@ -468,7 +468,7 @@ public boolean exists(Specification<T> spec) {
}

@Override
public long delete(Specification<T> spec) {
public long delete(Specification<? super T> spec) {

CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
CriteriaDelete<T> delete = builder.createCriteriaDelete(getDomainClass());
Expand All @@ -485,23 +485,23 @@ public long delete(Specification<T> spec) {
}

@Override
public <S extends T, R> R findBy(Specification<T> spec, Function<FetchableFluentQuery<S>, R> queryFunction) {
public <S extends T, R> R findBy(Specification<? super T> spec, Function<FetchableFluentQuery<S>, R> queryFunction) {

Assert.notNull(spec, "Specification must not be null");
Assert.notNull(queryFunction, "Query function must not be null");

return doFindBy(spec, getDomainClass(), queryFunction);
}

private <S extends T, R> R doFindBy(Specification<T> spec, Class<T> domainClass,
private <S extends T, R> R doFindBy(Specification<? super T> spec, Class<T> domainClass,
Function<FetchableFluentQuery<S>, R> queryFunction) {

Assert.notNull(spec, "Specification must not be null");
Assert.notNull(queryFunction, "Query function must not be null");

ScrollQueryFactory scrollFunction = (sort, scrollPosition) -> {

Specification<T> specToUse = spec;
Specification<? super T> specToUse = spec;

if (scrollPosition instanceof KeysetScrollPosition keyset) {
KeysetScrollSpecification<T> keysetSpec = new KeysetScrollSpecification<>(keyset, sort, entityInformation);
Expand Down Expand Up @@ -604,7 +604,7 @@ public long count() {
}

@Override
public long count(@Nullable Specification<T> spec) {
public long count(@Nullable Specification<? super T> spec) {
return executeCountQuery(getCountQuery(spec, getDomainClass()));
}

Expand Down Expand Up @@ -687,7 +687,7 @@ protected Page<T> readPage(TypedQuery<T> query, Pageable pageable, @Nullable Spe
* @param pageable can be {@literal null}.
*/
protected <S extends T> Page<S> readPage(TypedQuery<S> query, final Class<S> domainClass, Pageable pageable,
@Nullable Specification<S> spec) {
@Nullable Specification<? super S> spec) {

if (pageable.isPaged()) {
query.setFirstResult(PageableUtils.getOffsetAsInteger(pageable));
Expand All @@ -704,7 +704,7 @@ protected <S extends T> Page<S> readPage(TypedQuery<S> query, final Class<S> dom
* @param spec can be {@literal null}.
* @param pageable must not be {@literal null}.
*/
protected TypedQuery<T> getQuery(@Nullable Specification<T> spec, Pageable pageable) {
protected TypedQuery<T> getQuery(@Nullable Specification<? super T> spec, Pageable pageable) {

Sort sort = pageable.isPaged() ? pageable.getSort() : Sort.unsorted();
return getQuery(spec, getDomainClass(), sort);
Expand All @@ -717,7 +717,7 @@ protected TypedQuery<T> getQuery(@Nullable Specification<T> spec, Pageable pagea
* @param domainClass must not be {@literal null}.
* @param pageable must not be {@literal null}.
*/
protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec, Class<S> domainClass,
protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<? super S> spec, Class<S> domainClass,
Pageable pageable) {

Sort sort = pageable.isPaged() ? pageable.getSort() : Sort.unsorted();
Expand All @@ -730,7 +730,7 @@ protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec,
* @param spec can be {@literal null}.
* @param sort must not be {@literal null}.
*/
protected TypedQuery<T> getQuery(@Nullable Specification<T> spec, Sort sort) {
protected TypedQuery<T> getQuery(@Nullable Specification<? super T> spec, Sort sort) {
return getQuery(spec, getDomainClass(), sort);
}

Expand All @@ -741,12 +741,13 @@ protected TypedQuery<T> getQuery(@Nullable Specification<T> spec, Sort sort) {
* @param domainClass must not be {@literal null}.
* @param sort must not be {@literal null}.
*/
protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec, Class<S> domainClass, Sort sort) {
protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<? super S> spec, Class<S> domainClass,
Sort sort) {

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<S> query = builder.createQuery(domainClass);

Root<S> root = applySpecificationToCriteria(spec, domainClass, query);
Root<? extends S> root = applySpecificationToCriteria(spec, domainClass, query);
query.select(root);

if (sort.isSorted()) {
Expand All @@ -773,7 +774,8 @@ protected TypedQuery<Long> getCountQuery(@Nullable Specification<T> spec) {
* @param spec can be {@literal null}.
* @param domainClass must not be {@literal null}.
*/
protected <S extends T> TypedQuery<Long> getCountQuery(@Nullable Specification<S> spec, Class<S> domainClass) {
protected <S extends T> TypedQuery<Long> getCountQuery(@Nullable Specification<? super S> spec,
Class<S> domainClass) {

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Long> query = builder.createQuery(Long.class);
Expand Down Expand Up @@ -814,8 +816,8 @@ protected QueryHints getQueryHintsForCount() {
* @param domainClass must not be {@literal null}.
* @param query must not be {@literal null}.
*/
private <S, U extends T> Root<U> applySpecificationToCriteria(@Nullable Specification<U> spec, Class<U> domainClass,
CriteriaQuery<S> query) {
private <S, U extends T> Root<U> applySpecificationToCriteria(@Nullable Specification<? super U> spec,
Class<U> domainClass, CriteriaQuery<S> query) {

Assert.notNull(domainClass, "Domain class must not be null");
Assert.notNull(query, "CriteriaQuery must not be null");
Expand Down Expand Up @@ -942,7 +944,7 @@ private static final class ByIdsSpecification<T> implements Specification<T> {
}

@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
public Predicate toPredicate(Root<? extends T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {

Path<?> path = root.get(entityInformation.getIdAttribute());
parameter = (ParameterExpression<Collection<?>>) (ParameterExpression) cb.parameter(Collection.class);
Expand Down Expand Up @@ -981,7 +983,7 @@ private static class ExampleSpecification<T> implements Specification<T> {
}

@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
public Predicate toPredicate(Root<? extends T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return QueryByExamplePredicateBuilder.getPredicate(root, cb, example, escapeCharacter);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ void orCombinesSpecificationsInOrder() {
static class SerializableSpecification implements Serializable, Specification<Object> {

@Override
public Predicate toPredicate(Root<Object> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
public Predicate toPredicate(Root<?> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return null;
}
}
Expand Down
Loading