Polishing.
Fix version reference to Spring Data Commons. Avoid stream creation when fetching all/one/first element. Move off deprecated API. Add override comments. Add null guargs. See #2294 Original pull request: #2326.
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -25,7 +25,7 @@
|
||||
<hibernate>5.5.3.Final</hibernate>
|
||||
<mysql-connector-java>8.0.23</mysql-connector-java>
|
||||
<postgresql>42.2.19</postgresql>
|
||||
<springdata.commons>2.6.0-2228-SNAPSHOT</springdata.commons>
|
||||
<springdata.commons>2.6.0-SNAPSHOT</springdata.commons>
|
||||
<vavr>0.10.3</vavr>
|
||||
|
||||
<hibernate.groupId>org.hibernate</hibernate.groupId>
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
@@ -37,6 +37,7 @@ import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
|
||||
import org.springframework.data.support.PageableExecutionUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Immutable implementation of {@link FetchableFluentQuery} based on Query by {@link Example}. All methods that return a
|
||||
@@ -45,6 +46,7 @@ import org.springframework.lang.Nullable;
|
||||
* @param <S> Domain type
|
||||
* @param <R> Result type
|
||||
* @author Greg Turnquist
|
||||
* @author Mark Paluch
|
||||
* @since 2.6
|
||||
*/
|
||||
class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<R> implements FetchableFluentQuery<R> {
|
||||
@@ -79,24 +81,39 @@ class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<R> implemen
|
||||
this.escapeCharacter = escapeCharacter;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#sortBy(org.springframework.data.domain.Sort)
|
||||
*/
|
||||
@Override
|
||||
public FetchableFluentQuery<R> sortBy(Sort sort) {
|
||||
|
||||
return new FetchableFluentQueryByExample<S, R>(this.example, this.resultType, this.sort.and(sort), this.properties,
|
||||
Assert.notNull(sort, "Sort must not be null!");
|
||||
|
||||
return new FetchableFluentQueryByExample<>(this.example, this.resultType, this.sort.and(sort), this.properties,
|
||||
this.finder, this.countOperation, this.existsOperation, this.context, this.entityManager, this.escapeCharacter);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#as(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <NR> FetchableFluentQuery<NR> as(Class<NR> resultType) {
|
||||
|
||||
Assert.notNull(resultType, "Projection target type must not be null!");
|
||||
if (!resultType.isInterface()) {
|
||||
throw new UnsupportedOperationException("Class-based DTOs are not yet supported.");
|
||||
}
|
||||
|
||||
return new FetchableFluentQueryByExample<S, NR>(this.example, resultType, this.sort, this.properties, this.finder,
|
||||
return new FetchableFluentQueryByExample<>(this.example, resultType, this.sort, this.properties, this.finder,
|
||||
this.countOperation, this.existsOperation, this.context, this.entityManager, this.escapeCharacter);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#project(java.util.Collection)
|
||||
*/
|
||||
@Override
|
||||
public FetchableFluentQuery<R> project(Collection<String> properties) {
|
||||
|
||||
@@ -104,62 +121,86 @@ class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<R> implemen
|
||||
this.finder, this.countOperation, this.existsOperation, this.context, this.entityManager, this.escapeCharacter);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#oneValue()
|
||||
*/
|
||||
@Override
|
||||
public R oneValue() {
|
||||
|
||||
TypedQuery<S> limitedQuery = this.finder.apply(this.sort);
|
||||
limitedQuery.setMaxResults(2); // Never need more than 2 values
|
||||
|
||||
List<R> results = limitedQuery //
|
||||
.getResultStream() //
|
||||
.map(getConversionFunction(this.example.getProbeType(), this.resultType)) //
|
||||
.collect(Collectors.toList());
|
||||
;
|
||||
List<S> results = limitedQuery.getResultList();
|
||||
|
||||
if (results.size() > 1) {
|
||||
throw new IncorrectResultSizeDataAccessException(1);
|
||||
}
|
||||
|
||||
return results.isEmpty() ? null : results.get(0);
|
||||
return results.isEmpty() ? null : getConversionFunction().apply(results.get(0));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#firstValue()
|
||||
*/
|
||||
@Override
|
||||
public R firstValue() {
|
||||
|
||||
TypedQuery<S> limitedQuery = this.finder.apply(this.sort);
|
||||
limitedQuery.setMaxResults(1); // Never need more than 1 value
|
||||
|
||||
List<R> results = limitedQuery //
|
||||
.getResultStream() //
|
||||
.map(getConversionFunction(this.example.getProbeType(), this.resultType)) //
|
||||
.collect(Collectors.toList());
|
||||
List<S> results = limitedQuery.getResultList();
|
||||
|
||||
return results.isEmpty() ? null : results.get(0);
|
||||
return results.isEmpty() ? null : getConversionFunction().apply(results.get(0));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#all()
|
||||
*/
|
||||
@Override
|
||||
public List<R> all() {
|
||||
return stream().collect(Collectors.toList());
|
||||
|
||||
List<S> resultList = this.finder.apply(this.sort).getResultList();
|
||||
|
||||
return convert(resultList);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#page(org.springframework.data.domain.Pageable)
|
||||
*/
|
||||
@Override
|
||||
public Page<R> page(Pageable pageable) {
|
||||
return pageable.isUnpaged() ? new PageImpl<>(all()) : readPage(pageable);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#stream()
|
||||
*/
|
||||
@Override
|
||||
public Stream<R> stream() {
|
||||
|
||||
return this.finder.apply(this.sort) //
|
||||
.getResultStream() //
|
||||
.map(getConversionFunction(this.example.getProbeType(), this.resultType));
|
||||
.map(getConversionFunction());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#count()
|
||||
*/
|
||||
@Override
|
||||
public long count() {
|
||||
return this.countOperation.apply(example);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#exists()
|
||||
*/
|
||||
@Override
|
||||
public boolean exists() {
|
||||
return this.existsOperation.apply(example);
|
||||
@@ -174,10 +215,24 @@ class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<R> implemen
|
||||
pagedQuery.setMaxResults(pageable.getPageSize());
|
||||
}
|
||||
|
||||
List<R> paginatedResults = pagedQuery.getResultStream() //
|
||||
.map(getConversionFunction(this.example.getProbeType(), this.resultType)) //
|
||||
.collect(Collectors.toList());
|
||||
List<R> paginatedResults = convert(pagedQuery.getResultList());
|
||||
|
||||
return PageableExecutionUtils.getPage(paginatedResults, pageable, () -> this.countOperation.apply(this.example));
|
||||
}
|
||||
|
||||
private List<R> convert(List<S> resultList) {
|
||||
|
||||
Function<Object, R> conversionFunction = getConversionFunction();
|
||||
List<R> mapped = new ArrayList<>(resultList.size());
|
||||
|
||||
for (S s : resultList) {
|
||||
mapped.add(conversionFunction.apply(s));
|
||||
}
|
||||
return mapped;
|
||||
}
|
||||
|
||||
private Function<Object, R> getConversionFunction() {
|
||||
return getConversionFunction(this.example.getProbeType(), this.resultType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
@@ -33,6 +33,7 @@ import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
|
||||
import org.springframework.data.support.PageableExecutionUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.querydsl.core.types.Predicate;
|
||||
import com.querydsl.jpa.JPQLQuery;
|
||||
@@ -44,6 +45,7 @@ import com.querydsl.jpa.JPQLQuery;
|
||||
* @param <S> Domain type
|
||||
* @param <R> Result type
|
||||
* @author Greg Turnquist
|
||||
* @author Mark Paluch
|
||||
* @since 2.6
|
||||
*/
|
||||
class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<R> implements FetchableFluentQuery<R> {
|
||||
@@ -78,16 +80,27 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<R> implem
|
||||
this.entityType = entityType;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#sortBy(org.springframework.data.domain.Sort)
|
||||
*/
|
||||
@Override
|
||||
public FetchableFluentQuery<R> sortBy(Sort sort) {
|
||||
|
||||
Assert.notNull(sort, "Sort must not be null!");
|
||||
|
||||
return new FetchableFluentQueryByPredicate<>(this.predicate, this.resultType, this.sort.and(sort), this.properties,
|
||||
this.finder, this.pagedFinder, this.countOperation, this.existsOperation, this.entityType, this.context);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#as(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <NR> FetchableFluentQuery<NR> as(Class<NR> resultType) {
|
||||
|
||||
Assert.notNull(resultType, "Projection target type must not be null!");
|
||||
if (!resultType.isInterface()) {
|
||||
throw new UnsupportedOperationException("Class-based DTOs are not yet supported.");
|
||||
}
|
||||
@@ -96,6 +109,10 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<R> implem
|
||||
this.pagedFinder, this.countOperation, this.existsOperation, this.entityType, this.context);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#project(java.util.Collection)
|
||||
*/
|
||||
@Override
|
||||
public FetchableFluentQuery<R> project(Collection<String> properties) {
|
||||
|
||||
@@ -104,57 +121,83 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<R> implem
|
||||
this.entityType, this.context);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#oneValue()
|
||||
*/
|
||||
@Override
|
||||
public R oneValue() {
|
||||
|
||||
List<R> results = this.finder.apply(this.sort) //
|
||||
List<S> results = this.finder.apply(this.sort) //
|
||||
.limit(2) // Never need more than 2 values
|
||||
.stream() //
|
||||
.map(getConversionFunction(this.entityType, this.resultType)) //
|
||||
.collect(Collectors.toList());
|
||||
.fetch();
|
||||
|
||||
if (results.size() > 1) {
|
||||
throw new IncorrectResultSizeDataAccessException(1);
|
||||
}
|
||||
|
||||
return results.isEmpty() ? null : results.get(0);
|
||||
return results.isEmpty() ? null : getConversionFunction().apply(results.get(0));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#firstValue()
|
||||
*/
|
||||
@Override
|
||||
public R firstValue() {
|
||||
|
||||
List<R> results = this.finder.apply(this.sort) //
|
||||
List<S> results = this.finder.apply(this.sort) //
|
||||
.limit(1) // Never need more than 1 value
|
||||
.stream() //
|
||||
.map(getConversionFunction(this.entityType, this.resultType)) //
|
||||
.collect(Collectors.toList());
|
||||
.fetch();
|
||||
|
||||
return results.isEmpty() ? null : results.get(0);
|
||||
return results.isEmpty() ? null : getConversionFunction().apply(results.get(0));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#all()
|
||||
*/
|
||||
@Override
|
||||
public List<R> all() {
|
||||
return stream().collect(Collectors.toList());
|
||||
|
||||
JPQLQuery<S> query = this.finder.apply(this.sort);
|
||||
return convert(query.fetch());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#page(org.springframework.data.domain.Pageable)
|
||||
*/
|
||||
@Override
|
||||
public Page<R> page(Pageable pageable) {
|
||||
return pageable.isUnpaged() ? new PageImpl<>(all()) : readPage(pageable);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#stream()
|
||||
*/
|
||||
@Override
|
||||
public Stream<R> stream() {
|
||||
|
||||
return this.finder.apply(this.sort) //
|
||||
.stream() //
|
||||
.map(getConversionFunction(this.entityType, this.resultType));
|
||||
.map(getConversionFunction());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#count()
|
||||
*/
|
||||
@Override
|
||||
public long count() {
|
||||
return this.countOperation.apply(this.predicate);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#exists()
|
||||
*/
|
||||
@Override
|
||||
public boolean exists() {
|
||||
return this.existsOperation.apply(this.predicate);
|
||||
@@ -163,11 +206,25 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<R> implem
|
||||
private Page<R> readPage(Pageable pageable) {
|
||||
|
||||
JPQLQuery<S> pagedQuery = this.pagedFinder.apply(this.sort, pageable);
|
||||
|
||||
List<R> paginatedResults = pagedQuery.stream() //
|
||||
.map(getConversionFunction(this.entityType, this.resultType)) //
|
||||
.collect(Collectors.toList());
|
||||
List<R> paginatedResults = convert(pagedQuery.fetch());
|
||||
|
||||
return PageableExecutionUtils.getPage(paginatedResults, pageable, () -> this.countOperation.apply(this.predicate));
|
||||
}
|
||||
|
||||
private List<R> convert(List<S> resultList) {
|
||||
|
||||
Function<Object, R> conversionFunction = getConversionFunction();
|
||||
List<R> mapped = new ArrayList<>(resultList.size());
|
||||
|
||||
for (S s : resultList) {
|
||||
mapped.add(conversionFunction.apply(s));
|
||||
}
|
||||
|
||||
return mapped;
|
||||
}
|
||||
|
||||
private Function<Object, R> getConversionFunction() {
|
||||
return getConversionFunction(this.entityType, this.resultType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ import org.springframework.data.querydsl.EntityPathResolver;
|
||||
import org.springframework.data.querydsl.QSort;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
|
||||
import org.springframework.data.repository.support.PageableExecutionUtils;
|
||||
import org.springframework.data.support.PageableExecutionUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -167,11 +167,16 @@ public class QuerydslJpaPredicateExecutor<T> implements QuerydslPredicateExecuto
|
||||
return PageableExecutionUtils.getPage(query.fetch(), pageable, countQuery::fetchCount);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findBy(com.querydsl.core.types.Predicate, java.util.function.Function)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <S extends T, R> R findBy(Predicate predicate, Function<FetchableFluentQuery<S>, R> queryFunction) {
|
||||
|
||||
Assert.notNull(predicate, "Predicate must not be null!");
|
||||
Assert.notNull(queryFunction, "Function must not be null!");
|
||||
Assert.notNull(queryFunction, "Query function must not be null!");
|
||||
|
||||
Function<Sort, JPQLQuery<T>> finder = sort -> {
|
||||
JPQLQuery<T> select = createQuery(predicate).select(path);
|
||||
@@ -194,12 +199,12 @@ public class QuerydslJpaPredicateExecutor<T> implements QuerydslPredicateExecuto
|
||||
return select;
|
||||
};
|
||||
|
||||
FetchableFluentQuery<S> fluentQuery = (FetchableFluentQuery<S>) new FetchableFluentQueryByPredicate<>(predicate,
|
||||
FetchableFluentQueryByPredicate<T, T> fluentQuery = new FetchableFluentQueryByPredicate<>(predicate,
|
||||
entityInformation.getJavaType(), finder, pagedFinder, this::count, this::exists,
|
||||
this.entityInformation.getJavaType(),
|
||||
new JpaMetamodelMappingContext(Collections.singleton(this.entityManager.getMetamodel())));
|
||||
|
||||
return queryFunction.apply(fluentQuery);
|
||||
return queryFunction.apply((FetchableFluentQuery<S>) fluentQuery);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -58,7 +58,7 @@ import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
|
||||
import org.springframework.data.repository.support.PageableExecutionUtils;
|
||||
import org.springframework.data.support.PageableExecutionUtils;
|
||||
import org.springframework.data.util.ProxyUtils;
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -583,6 +583,9 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
||||
@Override
|
||||
public <S extends T, R> R findBy(Example<S> example, Function<FetchableFluentQuery<S>, R> queryFunction) {
|
||||
|
||||
Assert.notNull(example, "Sample must not be null!");
|
||||
Assert.notNull(queryFunction, "Query function must not be null!");
|
||||
|
||||
Function<Sort, TypedQuery<S>> finder = sort -> {
|
||||
|
||||
ExampleSpecification<S> spec = new ExampleSpecification<>(example, escapeCharacter);
|
||||
|
||||
Reference in New Issue
Block a user