DATAJPA-872 - Allow for duplicate hints.
Some JPA implementations allow to have multiple hints for the same key/name. The former implementation did not support that since it stored hints as Maps. With this change they are now stored as lists and duplicates are passed on to the JPA implementation. How the implementation deals with such a situation depends on that implementation. Original pull request: #426.
This commit is contained in:
committed by
Mark Paluch
parent
70d43844d0
commit
4b7f9e91c5
@@ -41,6 +41,8 @@ import org.springframework.data.jpa.repository.query.JpaQueryExecution.Procedure
|
||||
import org.springframework.data.jpa.repository.query.JpaQueryExecution.SingleEntityExecution;
|
||||
import org.springframework.data.jpa.repository.query.JpaQueryExecution.SlicedExecution;
|
||||
import org.springframework.data.jpa.repository.query.JpaQueryExecution.StreamExecution;
|
||||
import org.springframework.data.jpa.repository.support.QueryHintValue;
|
||||
import org.springframework.data.jpa.repository.support.SimpleQueryHints;
|
||||
import org.springframework.data.jpa.util.JpaMetamodel;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.data.repository.query.ResultProcessor;
|
||||
@@ -239,12 +241,10 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
|
||||
JpaEntityGraph entityGraph = method.getEntityGraph();
|
||||
|
||||
if (entityGraph != null) {
|
||||
Map<String, Object> hints = Jpa21Utils.tryGetFetchGraphHints(em, method.getEntityGraph(),
|
||||
SimpleQueryHints hints = Jpa21Utils.getFetchGraphHint(em, method.getEntityGraph(),
|
||||
getQueryMethod().getEntityInformation().getJavaType());
|
||||
|
||||
for (Map.Entry<String, Object> hint : hints.entrySet()) {
|
||||
query.setHint(hint.getKey(), hint.getValue());
|
||||
}
|
||||
hints.forEach(query::setHint);
|
||||
}
|
||||
|
||||
return query;
|
||||
|
||||
@@ -27,6 +27,8 @@ import javax.persistence.EntityManager;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.Subgraph;
|
||||
|
||||
import org.springframework.data.jpa.repository.support.QueryHintValue;
|
||||
import org.springframework.data.jpa.repository.support.SimpleQueryHints;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -41,6 +43,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @author Jens Schauder
|
||||
* @since 1.6
|
||||
*/
|
||||
public class Jpa21Utils {
|
||||
@@ -62,29 +65,23 @@ public class Jpa21Utils {
|
||||
// prevent instantiation
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Map} with hints for a JPA 2.1 fetch-graph or load-graph if running under JPA 2.1.
|
||||
*
|
||||
* @param em must not be {@literal null}.
|
||||
* @param entityGraph can be {@literal null}.
|
||||
* @param entityType must not be {@literal null}.
|
||||
* @return a {@code Map} with the hints or an empty {@code Map} if no hints were found.
|
||||
* @since 1.8
|
||||
*/
|
||||
public static Map<String, Object> tryGetFetchGraphHints(EntityManager em, @Nullable JpaEntityGraph entityGraph,
|
||||
public static SimpleQueryHints getFetchGraphHint(EntityManager em, @Nullable JpaEntityGraph entityGraph,
|
||||
Class<?> entityType) {
|
||||
|
||||
SimpleQueryHints result = new SimpleQueryHints();
|
||||
|
||||
if (entityGraph == null) {
|
||||
return Collections.emptyMap();
|
||||
return result;
|
||||
}
|
||||
|
||||
EntityGraph<?> graph = tryGetFetchGraph(em, entityGraph, entityType);
|
||||
|
||||
if (graph == null) {
|
||||
return Collections.emptyMap();
|
||||
return result;
|
||||
}
|
||||
|
||||
return Collections.<String, Object> singletonMap(entityGraph.getType().getKey(), graph);
|
||||
result.add(entityGraph.getType().getKey(), graph);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,8 +16,12 @@
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import javax.persistence.LockModeType;
|
||||
|
||||
@@ -45,22 +49,20 @@ public interface CrudMethodMetadata {
|
||||
LockModeType getLockModeType();
|
||||
|
||||
/**
|
||||
* Returns all query hints to be applied to queries executed for the CRUD method.
|
||||
*
|
||||
* Returns all query hints in a list to be applied to queries executed for the CRUD method.
|
||||
*
|
||||
* @return
|
||||
* @since 2.4
|
||||
*/
|
||||
Map<String, Object> getQueryHints();
|
||||
SimpleQueryHints getQueryHints();
|
||||
|
||||
/**
|
||||
* Returns all query hints to be applied to count queries executed for the CRUD method. The default implementation
|
||||
* just delegates to {@link #getQueryHints()}.
|
||||
*
|
||||
* Returns all query hints in a list to be applied to queries executed for the CRUD method.
|
||||
*
|
||||
* @return
|
||||
* @since 2.2
|
||||
* @since 2.4
|
||||
*/
|
||||
default Map<String, Object> getQueryHintsForCount() {
|
||||
return getQueryHints();
|
||||
}
|
||||
SimpleQueryHints getQueryHintsForCount();
|
||||
|
||||
/**
|
||||
* Returns the {@link EntityGraph} to be used.
|
||||
|
||||
@@ -16,10 +16,8 @@
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -31,7 +29,6 @@ import javax.persistence.QueryHint;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
@@ -194,8 +191,8 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
|
||||
private static class DefaultCrudMethodMetadata implements CrudMethodMetadata {
|
||||
|
||||
private final @Nullable LockModeType lockModeType;
|
||||
private final Map<String, Object> queryHints;
|
||||
private final Map<String, Object> getQueryHintsForCount;
|
||||
private final SimpleQueryHints queryHints;
|
||||
private final SimpleQueryHints queryHintsForCount;
|
||||
private final Optional<EntityGraph> entityGraph;
|
||||
private final Method method;
|
||||
|
||||
@@ -210,7 +207,7 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
|
||||
|
||||
this.lockModeType = findLockModeType(method);
|
||||
this.queryHints = findQueryHints(method, it -> true);
|
||||
this.getQueryHintsForCount = findQueryHints(method, QueryHints::forCounting);
|
||||
this.queryHintsForCount = findQueryHints(method, QueryHints::forCounting);
|
||||
this.entityGraph = findEntityGraph(method);
|
||||
this.method = method;
|
||||
}
|
||||
@@ -226,25 +223,26 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
|
||||
return annotation == null ? null : (LockModeType) AnnotationUtils.getValue(annotation);
|
||||
}
|
||||
|
||||
private static Map<String, Object> findQueryHints(Method method, Predicate<QueryHints> annotationFilter) {
|
||||
private static SimpleQueryHints findQueryHints(Method method, Predicate<QueryHints> annotationFilter) {
|
||||
|
||||
SimpleQueryHints queryHints = new SimpleQueryHints();
|
||||
|
||||
Map<String, Object> queryHints = new HashMap<>();
|
||||
QueryHints queryHintsAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, QueryHints.class);
|
||||
|
||||
if (queryHintsAnnotation != null && annotationFilter.test(queryHintsAnnotation)) {
|
||||
|
||||
for (QueryHint hint : queryHintsAnnotation.value()) {
|
||||
queryHints.put(hint.name(), hint.value());
|
||||
queryHints.add(hint.name(), hint.value());
|
||||
}
|
||||
}
|
||||
|
||||
QueryHint queryHintAnnotation = AnnotationUtils.findAnnotation(method, QueryHint.class);
|
||||
|
||||
if (queryHintAnnotation != null) {
|
||||
queryHints.put(queryHintAnnotation.name(), queryHintAnnotation.value());
|
||||
queryHints.add(queryHintAnnotation.name(), queryHintAnnotation.value());
|
||||
}
|
||||
|
||||
return Collections.unmodifiableMap(queryHints);
|
||||
return queryHints;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -257,22 +255,14 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
|
||||
return lockModeType;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.support.CrudMethodMetadata#getQueryHints()
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getQueryHints() {
|
||||
public SimpleQueryHints getQueryHints() {
|
||||
return queryHints;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.support.CrudMethodMetadata#getQueryHintsForCount()
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getQueryHintsForCount() {
|
||||
return getQueryHintsForCount;
|
||||
public SimpleQueryHints getQueryHintsForCount() {
|
||||
return queryHintsForCount;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -15,12 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
@@ -97,41 +93,26 @@ class DefaultQueryHints implements QueryHints {
|
||||
return new DefaultQueryHints(this.information, this.metadata, this.entityManager, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Entry<String, Object>> iterator() {
|
||||
return asMap().entrySet().iterator();
|
||||
public void forEach(BiConsumer<String, Object> consumer) {
|
||||
combineHints().forEach(consumer);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.support.QueryHints#asMap()
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> asMap() {
|
||||
private SimpleQueryHints combineHints() {
|
||||
|
||||
Map<String, Object> hints = new HashMap<>();
|
||||
SimpleQueryHints hints = forCounts ? metadata.getQueryHintsForCount() : metadata.getQueryHints();
|
||||
|
||||
if (forCounts) {
|
||||
hints.putAll(metadata.getQueryHintsForCount());
|
||||
} else {
|
||||
hints.putAll(metadata.getQueryHints());
|
||||
}
|
||||
|
||||
hints.putAll(getFetchGraphs());
|
||||
hints.addAll(getFetchGraphs());
|
||||
|
||||
return hints;
|
||||
}
|
||||
|
||||
private Map<String, Object> getFetchGraphs() {
|
||||
private SimpleQueryHints getFetchGraphs() {
|
||||
|
||||
return Optionals
|
||||
.mapIfAllPresent(entityManager, metadata.getEntityGraph(),
|
||||
(em, graph) -> Jpa21Utils.tryGetFetchGraphHints(em, getEntityGraph(graph), information.getJavaType()))
|
||||
.orElse(Collections.emptyMap());
|
||||
(em, graph) -> Jpa21Utils.getFetchGraphHint(em, getEntityGraph(graph), information.getJavaType()))
|
||||
.orElse(new SimpleQueryHints());
|
||||
}
|
||||
|
||||
private JpaEntityGraph getEntityGraph(EntityGraph entityGraph) {
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Value object carrying a query hint consisting of a name/key and a value.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @since 2.4
|
||||
*/
|
||||
public class QueryHintValue {
|
||||
|
||||
public final String name;
|
||||
public final Object value;
|
||||
|
||||
public QueryHintValue(String name, Object value) {
|
||||
|
||||
Assert.notNull(name, "Name must not be null.");
|
||||
Assert.notNull(value, "Value must not be null.");
|
||||
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "QueryHintValue{" + "name='" + name + '\'' + ", value='" + value + '\'' + '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
QueryHintValue that = (QueryHintValue) o;
|
||||
return name.equals(that.name) && value.equals(that.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, value);
|
||||
}
|
||||
}
|
||||
@@ -15,23 +15,21 @@
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
/**
|
||||
* QueryHints provides access to query hints defined via {@link CrudMethodMetadata#getQueryHints()} by default excluding
|
||||
* JPA {@link javax.persistence.EntityGraph}.
|
||||
* QueryHints provides access to query hints defined via {@link CrudMethodMetadata#getQueryHints()} QueryHintList()} by
|
||||
* default excluding JPA {@link javax.persistence.EntityGraph}. The object allows to switch between query hints for
|
||||
* count queries with or without fetch graph hints.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @author Jens Schauder
|
||||
* @since 2.0
|
||||
*/
|
||||
interface QueryHints extends Iterable<Entry<String, Object>> {
|
||||
interface QueryHints {
|
||||
|
||||
/**
|
||||
* Creates and returns a new {@link QueryHints} instance including {@link javax.persistence.EntityGraph}.
|
||||
@@ -51,11 +49,12 @@ interface QueryHints extends Iterable<Entry<String, Object>> {
|
||||
QueryHints forCounts();
|
||||
|
||||
/**
|
||||
* Get the query hints as a {@link Map}.
|
||||
* Passes each query hint to the consumer. Query hint keys might appear more than once.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
* @param consumer to process query hints consisting of a key and a value.
|
||||
* @since 2.4
|
||||
*/
|
||||
Map<String, Object> asMap();
|
||||
void forEach(BiConsumer<String, Object> consumer);
|
||||
|
||||
/**
|
||||
* Null object implementation of {@link QueryHints}.
|
||||
@@ -63,28 +62,10 @@ interface QueryHints extends Iterable<Entry<String, Object>> {
|
||||
* @author Oliver Gierke
|
||||
* @since 2.0
|
||||
*/
|
||||
static enum NoHints implements QueryHints {
|
||||
enum NoHints implements QueryHints {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.support.QueryHints#asMap()
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> asMap() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
@Override
|
||||
public Iterator<Entry<String, Object>> iterator() {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.support.QueryHints#withFetchGraphs(javax.persistence.EntityManager)
|
||||
@@ -102,5 +83,8 @@ interface QueryHints extends Iterable<Entry<String, Object>> {
|
||||
public QueryHints forCounts() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(BiConsumer<String, Object> consumer) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
@@ -245,9 +244,7 @@ public class QuerydslJpaPredicateExecutor<T> implements QuerydslPredicateExecuto
|
||||
query = query.where(predicate);
|
||||
}
|
||||
|
||||
for (Entry<String, Object> hint : hints) {
|
||||
query.setHint(hint.getKey(), hint.getValue());
|
||||
}
|
||||
hints.forEach(query::setHint);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
@@ -48,7 +47,6 @@ import com.querydsl.jpa.impl.AbstractJPAQuery;
|
||||
* {@link QuerydslPredicateExecutor}.
|
||||
*
|
||||
* @deprecated Instead of this class use {@link QuerydslJpaPredicateExecutor}
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
@@ -222,9 +220,7 @@ public class QuerydslJpaRepository<T, ID extends Serializable> extends SimpleJpa
|
||||
query = query.where(predicate);
|
||||
}
|
||||
|
||||
for (Entry<String, Object> hint : hints) {
|
||||
query.setHint(hint.getKey(), hint.getValue());
|
||||
}
|
||||
hints.forEach(query::setHint);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
@@ -20,9 +20,9 @@ import static org.springframework.data.jpa.repository.query.QueryUtils.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
@@ -276,7 +276,8 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
||||
|
||||
LockModeType type = metadata.getLockModeType();
|
||||
|
||||
Map<String, Object> hints = getQueryHints().withFetchGraphs(em).asMap();
|
||||
Map<String, Object> hints = new HashMap<>();
|
||||
getQueryHints().withFetchGraphs(em).forEach(hints::put);
|
||||
|
||||
return Optional.ofNullable(type == null ? em.find(domainType, id, hints) : em.find(domainType, id, type, hints));
|
||||
}
|
||||
@@ -785,10 +786,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
||||
}
|
||||
|
||||
private void applyQueryHints(Query query) {
|
||||
|
||||
for (Entry<String, Object> hint : getQueryHints().withFetchGraphs(em)) {
|
||||
query.setHint(hint.getKey(), hint.getValue());
|
||||
}
|
||||
getQueryHints().withFetchGraphs(em).forEach(query::setHint);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Just the values of QueryHints, without the Option to switch between count/ fetchGraph hints.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @since 2.4
|
||||
* @see QueryHints
|
||||
*/
|
||||
public class SimpleQueryHints {
|
||||
|
||||
MultiValueMap<String, Object> values = new LinkedMultiValueMap<>();
|
||||
|
||||
|
||||
public void add(String name, Object value) {
|
||||
values.add(name, value);
|
||||
}
|
||||
|
||||
public void forEach(BiConsumer<String, Object> consumer) {
|
||||
|
||||
for (Map.Entry<String, List<Object>> entry : values.entrySet()) {
|
||||
|
||||
for (Object value : entry.getValue()) {
|
||||
consumer.accept(entry.getKey(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addAll(SimpleQueryHints hints) {
|
||||
hints.forEach(this::add);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,9 @@ package org.springframework.data.jpa.repository.support;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -46,9 +48,14 @@ public class DefaultQueryHintsTest {
|
||||
|
||||
QueryHints hints = DefaultQueryHints.of(information, metadata);
|
||||
|
||||
assertThat(hints.asMap()) //
|
||||
.extracting("name1", "name2", "n1", "n2") //
|
||||
.containsExactly("value1", "value2", null, null);
|
||||
Map<String, Object> collectedHints=new HashMap<>();
|
||||
hints.forEach(collectedHints::put);
|
||||
|
||||
assertThat(collectedHints) //
|
||||
.contains( //
|
||||
entry("name1", "value1"), //
|
||||
entry("name2", "value2") //
|
||||
);
|
||||
}
|
||||
|
||||
@Test // DATAJPA-1156
|
||||
@@ -56,26 +63,31 @@ public class DefaultQueryHintsTest {
|
||||
|
||||
QueryHints hints = DefaultQueryHints.of(information, metadata).forCounts();
|
||||
|
||||
assertThat(hints.asMap()) //
|
||||
.extracting("name1", "name2", "n1", "n2") //
|
||||
.containsExactly(null, null, "1", "2");
|
||||
Map<String, Object> collectedHints=new HashMap<>();
|
||||
hints.forEach(collectedHints::put);
|
||||
|
||||
assertThat(collectedHints) //
|
||||
.contains( //
|
||||
entry("n1", "1"), //
|
||||
entry("n2", "2") //
|
||||
);
|
||||
}
|
||||
|
||||
private void setupMainHints() {
|
||||
|
||||
Map<String, Object> mainHintMap = new HashMap<>();
|
||||
mainHintMap.put("name1", "value1");
|
||||
mainHintMap.put("name2", "value2");
|
||||
SimpleQueryHints mainHints = new SimpleQueryHints();
|
||||
mainHints.add("name1", "value1");
|
||||
mainHints.add("name2", "value2");
|
||||
|
||||
when(metadata.getQueryHints()).thenReturn(mainHintMap);
|
||||
when(metadata.getQueryHints()).thenReturn(mainHints);
|
||||
}
|
||||
|
||||
private void setUpCountHints() {
|
||||
|
||||
Map<String, Object> countHintMap = new HashMap<>();
|
||||
countHintMap.put("n1", "1");
|
||||
countHintMap.put("n2", "2");
|
||||
SimpleQueryHints countHints = new SimpleQueryHints();
|
||||
countHints.add("n1", "1");
|
||||
countHints.add("n2", "2");
|
||||
|
||||
when(metadata.getQueryHintsForCount()).thenReturn(countHintMap);
|
||||
when(metadata.getQueryHintsForCount()).thenReturn(countHints);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,10 @@ public class SimpleJpaRepositoryUnitTests {
|
||||
when(em.createQuery(criteriaQuery)).thenReturn(query);
|
||||
when(em.createQuery(countCriteriaQuery)).thenReturn(countQuery);
|
||||
|
||||
SimpleQueryHints hints = new SimpleQueryHints();
|
||||
when(metadata.getQueryHints()).thenReturn(hints);
|
||||
when(metadata.getQueryHintsForCount()).thenReturn(hints);
|
||||
|
||||
repo = new SimpleJpaRepository<User, Integer>(information, em);
|
||||
repo.setRepositoryMethodMetadata(metadata);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package org.springframework.data.jpa.repository.support;/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.util.Pair;
|
||||
|
||||
public class SimpleQueryHintsUnitTests {
|
||||
|
||||
@Test
|
||||
public void emptyQueryHint() {
|
||||
new SimpleQueryHints().forEach((k, v) -> Assertions.fail("Empty SimpleQueryHints shouldn't contain a value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void queryHint() {
|
||||
|
||||
SimpleQueryHints hints = new SimpleQueryHints();
|
||||
hints.add("key", "value");
|
||||
hints.add("key", "other value");
|
||||
hints.add("other key", "another value");
|
||||
|
||||
List calls = new ArrayList();
|
||||
hints.forEach((k, v) -> calls.add(Pair.of(k, v)));
|
||||
|
||||
assertThat(calls).containsExactlyInAnyOrder(Pair.of("key", "value"), Pair.of("key", "other value"),
|
||||
Pair.of("other key", "another value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addingQueryHints() {
|
||||
|
||||
SimpleQueryHints hints = new SimpleQueryHints();
|
||||
hints.add("key", "value");
|
||||
hints.add("key", "other value");
|
||||
hints.add("other key", "another value");
|
||||
|
||||
SimpleQueryHints additionalHints = new SimpleQueryHints();
|
||||
additionalHints.add("key", "23");
|
||||
additionalHints.add("another key", "42");
|
||||
|
||||
hints.addAll(additionalHints);
|
||||
|
||||
List calls = new ArrayList();
|
||||
hints.forEach((k, v) -> calls.add(Pair.of(k, v)));
|
||||
|
||||
assertThat(calls).containsExactlyInAnyOrder(Pair.of("key", "value"), Pair.of("key", "other value"),Pair.of("key", "23"),
|
||||
Pair.of("other key", "another value"), Pair.of("another key", "42"));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user