diff --git a/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java index 556e866b8..541f9dd0b 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java @@ -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 hints = Jpa21Utils.tryGetFetchGraphHints(em, method.getEntityGraph(), + SimpleQueryHints hints = Jpa21Utils.getFetchGraphHint(em, method.getEntityGraph(), getQueryMethod().getEntityInformation().getJavaType()); - for (Map.Entry hint : hints.entrySet()) { - query.setHint(hint.getKey(), hint.getValue()); - } + hints.forEach(query::setHint); } return query; diff --git a/src/main/java/org/springframework/data/jpa/repository/query/Jpa21Utils.java b/src/main/java/org/springframework/data/jpa/repository/query/Jpa21Utils.java index 436cf569a..850d916c2 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/Jpa21Utils.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/Jpa21Utils.java @@ -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 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. singletonMap(entityGraph.getType().getKey(), graph); + result.add(entityGraph.getType().getKey(), graph); + return result; } /** diff --git a/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadata.java b/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadata.java index 57630317e..018104fb3 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadata.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadata.java @@ -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 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 getQueryHintsForCount() { - return getQueryHints(); - } + SimpleQueryHints getQueryHintsForCount(); /** * Returns the {@link EntityGraph} to be used. diff --git a/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java b/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java index 8b2bd3bca..0973e0eb0 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java @@ -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 queryHints; - private final Map getQueryHintsForCount; + private final SimpleQueryHints queryHints; + private final SimpleQueryHints queryHintsForCount; private final Optional 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 findQueryHints(Method method, Predicate annotationFilter) { + private static SimpleQueryHints findQueryHints(Method method, Predicate annotationFilter) { + + SimpleQueryHints queryHints = new SimpleQueryHints(); - Map 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 getQueryHints() { + public SimpleQueryHints getQueryHints() { return queryHints; } - /* - * (non-Javadoc) - * @see org.springframework.data.jpa.repository.support.CrudMethodMetadata#getQueryHintsForCount() - */ @Override - public Map getQueryHintsForCount() { - return getQueryHintsForCount; + public SimpleQueryHints getQueryHintsForCount() { + return queryHintsForCount; } /* diff --git a/src/main/java/org/springframework/data/jpa/repository/support/DefaultQueryHints.java b/src/main/java/org/springframework/data/jpa/repository/support/DefaultQueryHints.java index 6f35c8e0a..904b6f069 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/DefaultQueryHints.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/DefaultQueryHints.java @@ -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> iterator() { - return asMap().entrySet().iterator(); + public void forEach(BiConsumer consumer) { + combineHints().forEach(consumer); } - /* - * (non-Javadoc) - * @see org.springframework.data.jpa.repository.support.QueryHints#asMap() - */ - @Override - public Map asMap() { + private SimpleQueryHints combineHints() { - Map 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 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) { diff --git a/src/main/java/org/springframework/data/jpa/repository/support/QueryHintValue.java b/src/main/java/org/springframework/data/jpa/repository/support/QueryHintValue.java new file mode 100644 index 000000000..34edc2a26 --- /dev/null +++ b/src/main/java/org/springframework/data/jpa/repository/support/QueryHintValue.java @@ -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); + } +} diff --git a/src/main/java/org/springframework/data/jpa/repository/support/QueryHints.java b/src/main/java/org/springframework/data/jpa/repository/support/QueryHints.java index e68794d38..b147a92e0 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/QueryHints.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/QueryHints.java @@ -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> { +interface QueryHints { /** * Creates and returns a new {@link QueryHints} instance including {@link javax.persistence.EntityGraph}. @@ -51,11 +49,12 @@ interface QueryHints extends Iterable> { 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 asMap(); + void forEach(BiConsumer consumer); /** * Null object implementation of {@link QueryHints}. @@ -63,28 +62,10 @@ interface QueryHints extends Iterable> { * @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 asMap() { - return Collections.emptyMap(); - } - - /* - * (non-Javadoc) - * @see java.lang.Iterable#iterator() - */ - @Override - public Iterator> 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> { public QueryHints forCounts() { return this; } + + @Override + public void forEach(BiConsumer consumer) {} } } diff --git a/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaPredicateExecutor.java b/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaPredicateExecutor.java index 65233da04..6963328dc 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaPredicateExecutor.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaPredicateExecutor.java @@ -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 implements QuerydslPredicateExecuto query = query.where(predicate); } - for (Entry hint : hints) { - query.setHint(hint.getKey(), hint.getValue()); - } + hints.forEach(query::setHint); return query; } diff --git a/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaRepository.java b/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaRepository.java index 1ab72ce0b..7817f68b0 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaRepository.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaRepository.java @@ -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 extends SimpleJpa query = query.where(predicate); } - for (Entry hint : hints) { - query.setHint(hint.getKey(), hint.getValue()); - } + hints.forEach(query::setHint); return query; } diff --git a/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java b/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java index 3169abe10..f9181959b 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java @@ -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 implements JpaRepositoryImplementation hints = getQueryHints().withFetchGraphs(em).asMap(); + Map 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 implements JpaRepositoryImplementation hint : getQueryHints().withFetchGraphs(em)) { - query.setHint(hint.getKey(), hint.getValue()); - } + getQueryHints().withFetchGraphs(em).forEach(query::setHint); } /** diff --git a/src/main/java/org/springframework/data/jpa/repository/support/SimpleQueryHints.java b/src/main/java/org/springframework/data/jpa/repository/support/SimpleQueryHints.java new file mode 100644 index 000000000..10aff1f1e --- /dev/null +++ b/src/main/java/org/springframework/data/jpa/repository/support/SimpleQueryHints.java @@ -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 values = new LinkedMultiValueMap<>(); + + + public void add(String name, Object value) { + values.add(name, value); + } + + public void forEach(BiConsumer consumer) { + + for (Map.Entry> entry : values.entrySet()) { + + for (Object value : entry.getValue()) { + consumer.accept(entry.getKey(), value); + } + } + } + + public void addAll(SimpleQueryHints hints) { + hints.forEach(this::add); + } +} diff --git a/src/test/java/org/springframework/data/jpa/repository/support/DefaultQueryHintsTest.java b/src/test/java/org/springframework/data/jpa/repository/support/DefaultQueryHintsTest.java index a98f71ea4..98f7b1326 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/DefaultQueryHintsTest.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/DefaultQueryHintsTest.java @@ -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 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 collectedHints=new HashMap<>(); + hints.forEach(collectedHints::put); + + assertThat(collectedHints) // + .contains( // + entry("n1", "1"), // + entry("n2", "2") // + ); } private void setupMainHints() { - Map 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 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); } } diff --git a/src/test/java/org/springframework/data/jpa/repository/support/SimpleJpaRepositoryUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/support/SimpleJpaRepositoryUnitTests.java index 13a037e07..cc649efd6 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/SimpleJpaRepositoryUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/SimpleJpaRepositoryUnitTests.java @@ -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(information, em); repo.setRepositoryMethodMetadata(metadata); } diff --git a/src/test/java/org/springframework/data/jpa/repository/support/SimpleQueryHintsUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/support/SimpleQueryHintsUnitTests.java new file mode 100644 index 000000000..99d887d95 --- /dev/null +++ b/src/test/java/org/springframework/data/jpa/repository/support/SimpleQueryHintsUnitTests.java @@ -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")); + } + +}