diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/Query.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/Query.java
index 614bee69c..6a5aadaf1 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/Query.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/Query.java
@@ -80,10 +80,10 @@ public @interface Query {
String countName() default "";
/**
- * Define the {@link QueryRewriter} bean that should be applied to this query after the query is full assembled.
+ * Define a {@link QueryRewriter} that should be applied to the query string after the query is fully assembled.
*
* @return
* @since 3.0
*/
- Class extends QueryRewriter> queryRewriter() default QueryRewriter.NoopQueryRewriter.class;
+ Class extends QueryRewriter> queryRewriter() default QueryRewriter.IdentityQueryRewriter.class;
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/QueryRewriter.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/QueryRewriter.java
index d80a998c2..426a08df6 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/QueryRewriter.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/QueryRewriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2022 the original author or authors.
+ * Copyright 2022 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.
@@ -19,33 +19,41 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
/**
- * Callback to rewrite a query right before it's handed to the EntityManager.
+ * Callback to rewrite a query and apply sorting and pagination settings that cannot be applied based on a regularly
+ * detectable scheme.
+ *
+ * The underlying the query is the one right before it is used for query object creation, so everything that Spring Data
+ * and tools intends to do has been done. You can customize the query to apply final changes. Rewriting can only make
+ * use of already existing contextual data. That is, adding or replacing query text or reuse of bound parameters. Query
+ * rewriting must not add additional bindable parameters as these cannot be materialized.
*
* @author Greg Turnquist
+ * @author Mark Paluch
* @since 3.0
+ * @see jakarta.persistence.EntityManager#createQuery
+ * @see jakarta.persistence.EntityManager#createNativeQuery
*/
@FunctionalInterface
public interface QueryRewriter {
/**
- * The assembled query and current {@link Sort} settings are offered. This is the query right before it's handed to
- * the EntityManager, so everything that Spring Data and tools intends to do has been done. The user is able to make
- * any last minute changes.
- *
+ * Rewrite the assembled query with the given {@link Sort}.
+ *
* WARNING: No checks are performed before the transformed query is passed to the EntityManager.
- *
- * @param query - the assembled generated query, right before it's handed over to the EntityManager.
- * @param sort - current {@link Sort} settings provided by the method, or {@link Sort#unsorted()}} if there are none.
- * @return alter the query however you like.
+ *
+ * @param query the assembled query.
+ * @param sort current {@link Sort} settings provided by the method, or {@link Sort#unsorted()}} if there are none.
+ * @return the query to be used with the {@code EntityManager}.
*/
String rewrite(String query, Sort sort);
/**
- * This alternative is used to handle {@link Pageable}-based methods.
- *
- * @param query - the assembled generated query, right before it's handed over to the EntityManager.
- * @param pageRequest
- * @return
+ * Rewrite the assembled query with the given {@link Pageable}.
+ *
+ * @param query the assembled query.
+ * @param pageRequest current {@link Pageable} settings provided by the method, or {@link Pageable#unpaged()} if not
+ * paged.
+ * @return the query to be used with the {@code EntityManager}.
*/
default String rewrite(String query, Pageable pageRequest) {
return rewrite(query, pageRequest.getSort());
@@ -54,7 +62,9 @@ public interface QueryRewriter {
/**
* A {@link QueryRewriter} that doesn't change the query.
*/
- public class NoopQueryRewriter implements QueryRewriter {
+ enum IdentityQueryRewriter implements QueryRewriter {
+
+ INSTANCE;
@Override
public String rewrite(String query, Sort sort) {
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/cdi/QueryRewriterBeanManagerProvider.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/cdi/BeanManagerQueryRewriterProvider.java
similarity index 50%
rename from spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/cdi/QueryRewriterBeanManagerProvider.java
rename to spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/cdi/BeanManagerQueryRewriterProvider.java
index 8a4369da8..d83a578b0 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/cdi/QueryRewriterBeanManagerProvider.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/cdi/BeanManagerQueryRewriterProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2022 the original author or authors.
+ * Copyright 2022 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.
@@ -19,37 +19,52 @@ import jakarta.enterprise.context.spi.CreationalContext;
import jakarta.enterprise.inject.spi.Bean;
import jakarta.enterprise.inject.spi.BeanManager;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import java.util.Iterator;
+
+import org.springframework.beans.BeanUtils;
import org.springframework.data.jpa.repository.QueryRewriter;
+import org.springframework.data.jpa.repository.query.DelegatingQueryRewriter;
+import org.springframework.data.jpa.repository.query.JpaQueryMethod;
import org.springframework.data.jpa.repository.query.QueryRewriterProvider;
+import org.springframework.data.util.Lazy;
/**
* A {@link BeanManager}-based {@link QueryRewriterProvider}.
*
* @author Greg Turnquist
+ * @author Mark Paluch
* @since 3.0
*/
-public class QueryRewriterBeanManagerProvider extends QueryRewriterProvider {
-
- private static final Log LOGGER = LogFactory.getLog(QueryRewriterBeanManagerProvider.class);
+public class BeanManagerQueryRewriterProvider implements QueryRewriterProvider {
private final BeanManager beanManager;
- public QueryRewriterBeanManagerProvider(BeanManager beanManager) {
+ public BeanManagerQueryRewriterProvider(BeanManager beanManager) {
this.beanManager = beanManager;
}
@Override
- protected QueryRewriter extractQueryRewriterBean(Class extends QueryRewriter> queryRewriter) {
+ @SuppressWarnings("unchecked")
+ public QueryRewriter getQueryRewriter(JpaQueryMethod method) {
- try {
- Bean bean = (Bean) beanManager.getBeans(queryRewriter).iterator().next();
- CreationalContext context = beanManager.createCreationalContext(bean);
- return (QueryRewriter) beanManager.getReference(bean, queryRewriter, context);
- } catch (Exception e) {
- LOGGER.error(e.toString());
- return null;
+ Class extends QueryRewriter> queryRewriter = method.getQueryRewriter();
+ if (queryRewriter == QueryRewriter.IdentityQueryRewriter.class) {
+ return QueryRewriter.IdentityQueryRewriter.INSTANCE;
}
+
+ Iterator> iterator = beanManager.getBeans(queryRewriter).iterator();
+
+ if (iterator.hasNext()) {
+
+ Bean bean = (Bean) iterator.next();
+ CreationalContext context = beanManager.createCreationalContext(bean);
+ Lazy rewriter = Lazy
+ .of(() -> (QueryRewriter) beanManager.getReference(bean, queryRewriter, context));
+
+ return new DelegatingQueryRewriter(rewriter);
+ }
+
+ return BeanUtils.instantiateClass(queryRewriter);
}
+
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/cdi/JpaRepositoryBean.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/cdi/JpaRepositoryBean.java
index 3f9b522d2..01412b744 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/cdi/JpaRepositoryBean.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/cdi/JpaRepositoryBean.java
@@ -62,7 +62,7 @@ class JpaRepositoryBean extends CdiRepositoryBean {
Assert.notNull(entityManagerBean, "EntityManager bean must not be null!");
this.entityManagerBean = entityManagerBean;
- this.queryRewriterProvider = new QueryRewriterBeanManagerProvider(beanManager);
+ this.queryRewriterProvider = new BeanManagerQueryRewriterProvider(beanManager);
}
@Override
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java
index 6f4eb5bdb..20611985b 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java
@@ -18,10 +18,9 @@ package org.springframework.data.jpa.repository.query;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
-import java.util.function.Supplier;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.QueryRewriter;
@@ -46,14 +45,12 @@ import org.springframework.util.Assert;
*/
abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
- private static final Log LOGGER = LogFactory.getLog(AbstractStringBasedJpaQuery.class);
-
private final DeclaredQuery query;
private final DeclaredQuery countQuery;
private final QueryMethodEvaluationContextProvider evaluationContextProvider;
private final SpelExpressionParser parser;
private final QueryParameterSetter.QueryMetadataCache metadataCache = new QueryParameterSetter.QueryMetadataCache();
- private final Supplier queryRewriterSupplier;
+ private final QueryRewriter queryRewriter;
/**
* Creates a new {@link AbstractStringBasedJpaQuery} from the given {@link JpaQueryMethod}, {@link EntityManager} and
@@ -65,16 +62,18 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
* @param countQueryString must not be {@literal null}.
* @param evaluationContextProvider must not be {@literal null}.
* @param parser must not be {@literal null}.
+ * @param queryRewriter must not be {@literal null}.
*/
public AbstractStringBasedJpaQuery(JpaQueryMethod method, EntityManager em, String queryString,
- @Nullable String countQueryString, QueryMethodEvaluationContextProvider evaluationContextProvider,
- SpelExpressionParser parser, QueryRewriterProvider queryRewriterProvider) {
+ @Nullable String countQueryString, QueryRewriter queryRewriter, QueryMethodEvaluationContextProvider evaluationContextProvider,
+ SpelExpressionParser parser) {
super(method, em);
Assert.hasText(queryString, "Query string must not be null or empty!");
Assert.notNull(evaluationContextProvider, "ExpressionEvaluationContextProvider must not be null!");
Assert.notNull(parser, "Parser must not be null!");
+ Assert.notNull(queryRewriter, "QueryRewriter must not be null!");
this.evaluationContextProvider = evaluationContextProvider;
this.query = new ExpressionBasedStringQuery(queryString, method.getEntityInformation(), parser,
@@ -85,7 +84,7 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
method.isNativeQuery());
this.parser = parser;
- this.queryRewriterSupplier = queryRewriterProvider.of(method);
+ this.queryRewriter = queryRewriter;
Assert.isTrue(method.isNativeQuery() || !query.usesJdbcStyleParameters(),
"JDBC style parameters (?) are not supported for JPA queries.");
@@ -169,7 +168,7 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
/**
* Use the {@link QueryRewriter}, potentially rewrite the query, using relevant {@link Sort} and {@link Pageable}
* information.
- *
+ *
* @param originalQuery
* @param sort
* @param pageable
@@ -177,12 +176,6 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
*/
protected String potentiallyRewriteQuery(String originalQuery, Sort sort, @Nullable Pageable pageable) {
- QueryRewriter queryRewriter = this.queryRewriterSupplier.get();
-
- if (queryRewriter == null) {
- return originalQuery;
- }
-
return pageable != null && pageable.isPaged() //
? queryRewriter.rewrite(originalQuery, pageable) //
: queryRewriter.rewrite(originalQuery, sort);
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRewriterBeanFactoryProvider.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/BeanFactoryQueryRewriterProvider.java
similarity index 53%
rename from spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRewriterBeanFactoryProvider.java
rename to spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/BeanFactoryQueryRewriterProvider.java
index 102dc6c94..bf34780a4 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRewriterBeanFactoryProvider.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/BeanFactoryQueryRewriterProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2022 the original author or authors.
+ * Copyright 2022 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.
@@ -15,36 +15,38 @@
*/
package org.springframework.data.jpa.repository.query;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.beans.BeansException;
+import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.data.jpa.repository.QueryRewriter;
+import org.springframework.data.util.Lazy;
/**
* A {@link BeanFactory}-based {@link QueryRewriterProvider}.
*
* @author Greg Turnquist
+ * @author Mark Paluch
* @since 3.0
*/
-public class QueryRewriterBeanFactoryProvider extends QueryRewriterProvider {
-
- private static final Log LOGGER = LogFactory.getLog(QueryRewriterBeanFactoryProvider.class);
+public class BeanFactoryQueryRewriterProvider implements QueryRewriterProvider {
private final BeanFactory beanFactory;
- public QueryRewriterBeanFactoryProvider(BeanFactory beanFactory) {
+ public BeanFactoryQueryRewriterProvider(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
- protected QueryRewriter extractQueryRewriterBean(Class extends QueryRewriter> queryRewriter) {
+ @SuppressWarnings("unchecked")
+ public QueryRewriter getQueryRewriter(JpaQueryMethod method) {
- try {
- return beanFactory.getBean(queryRewriter);
- } catch (BeansException e) {
- LOGGER.error(e.toString());
- return null;
+ Class extends QueryRewriter> queryRewriter = method.getQueryRewriter();
+ if (queryRewriter == QueryRewriter.IdentityQueryRewriter.class) {
+ return QueryRewriter.IdentityQueryRewriter.INSTANCE;
}
+
+ Lazy rewriter = Lazy.of(() -> beanFactory.getBeanProvider((Class) queryRewriter)
+ .getIfAvailable(() -> BeanUtils.instantiateClass(queryRewriter)));
+
+ return new DelegatingQueryRewriter(rewriter);
}
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DelegatingQueryRewriter.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DelegatingQueryRewriter.java
new file mode 100644
index 000000000..27aec0f9a
--- /dev/null
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DelegatingQueryRewriter.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2022 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.query;
+
+import java.util.function.Supplier;
+
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.repository.QueryRewriter;
+
+/**
+ * Delegating {@link QueryRewriter} that delegates rewrite calls to a {@link QueryRewriter delegate} provided by a
+ * {@link Supplier}.
+ *
+ * @author Mark Paluch
+ * @since 3.0
+ */
+public class DelegatingQueryRewriter implements QueryRewriter {
+
+ private final Supplier delegate;
+
+ public DelegatingQueryRewriter(Supplier delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public String rewrite(String query, Sort sort) {
+ return delegate.get().rewrite(query, sort);
+ }
+
+ @Override
+ public String rewrite(String query, Pageable pageRequest) {
+ return delegate.get().rewrite(query, pageRequest);
+ }
+}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryFactory.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryFactory.java
index 83df010e5..63b0bffe6 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryFactory.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryFactory.java
@@ -17,6 +17,7 @@ package org.springframework.data.jpa.repository.query;
import jakarta.persistence.EntityManager;
+import org.springframework.data.jpa.repository.QueryRewriter;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.expression.spel.standard.SpelExpressionParser;
@@ -39,20 +40,20 @@ enum JpaQueryFactory {
*
* @param method must not be {@literal null}.
* @param em must not be {@literal null}.
- * @param queryString must not be {@literal null} or empty.
* @param countQueryString
+ * @param queryString must not be {@literal null}.
* @param evaluationContextProvider
* @return
*/
AbstractJpaQuery fromMethodWithQueryString(JpaQueryMethod method, EntityManager em, String queryString,
- @Nullable String countQueryString, QueryMethodEvaluationContextProvider evaluationContextProvider,
- QueryRewriterProvider queryRewriterProvider) {
+ @Nullable String countQueryString, QueryRewriter queryRewriter,
+ QueryMethodEvaluationContextProvider evaluationContextProvider) {
return method.isNativeQuery()
- ? new NativeJpaQuery(method, em, queryString, countQueryString, evaluationContextProvider, PARSER,
- queryRewriterProvider)
- : new SimpleJpaQuery(method, em, queryString, countQueryString, evaluationContextProvider, PARSER,
- queryRewriterProvider);
+ ? new NativeJpaQuery(method, em, queryString, countQueryString, queryRewriter, evaluationContextProvider,
+ PARSER)
+ : new SimpleJpaQuery(method, em, queryString, countQueryString, queryRewriter, evaluationContextProvider,
+ PARSER);
}
/**
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java
index 552c587af..5fba2b6a4 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java
@@ -22,6 +22,7 @@ import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.jpa.repository.QueryRewriter;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryMetadata;
@@ -83,14 +84,13 @@ public final class JpaQueryLookupStrategy {
@Override
public final RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
NamedQueries namedQueries) {
- return resolveQuery(queryMethodFactory.build(method, metadata, factory), em, namedQueries);
+ JpaQueryMethod queryMethod = queryMethodFactory.build(method, metadata, factory);
+ return resolveQuery(queryMethod, queryRewriterProvider.getQueryRewriter(queryMethod), em, namedQueries);
}
- protected abstract RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries);
+ protected abstract RepositoryQuery resolveQuery(JpaQueryMethod method, QueryRewriter queryRewriter,
+ EntityManager em, NamedQueries namedQueries);
- protected QueryRewriterProvider getQueryRewriterSupplier() {
- return queryRewriterProvider;
- }
}
/**
@@ -112,7 +112,8 @@ public final class JpaQueryLookupStrategy {
}
@Override
- protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries) {
+ protected RepositoryQuery resolveQuery(JpaQueryMethod method, QueryRewriter queryRewriter, EntityManager em,
+ NamedQueries namedQueries) {
return new PartTreeJpaQuery(method, em, escape);
}
}
@@ -145,7 +146,8 @@ public final class JpaQueryLookupStrategy {
}
@Override
- protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries) {
+ protected RepositoryQuery resolveQuery(JpaQueryMethod method, QueryRewriter queryRewriter, EntityManager em,
+ NamedQueries namedQueries) {
if (method.isProcedureQuery()) {
return JpaQueryFactory.INSTANCE.fromProcedureAnnotation(method, em);
@@ -159,13 +161,13 @@ public final class JpaQueryLookupStrategy {
}
return JpaQueryFactory.INSTANCE.fromMethodWithQueryString(method, em, method.getRequiredAnnotatedQuery(),
- getCountQuery(method, namedQueries, em), evaluationContextProvider, getQueryRewriterSupplier());
+ getCountQuery(method, namedQueries, em), queryRewriter, evaluationContextProvider);
}
String name = method.getNamedQueryName();
if (namedQueries.hasQuery(name)) {
return JpaQueryFactory.INSTANCE.fromMethodWithQueryString(method, em, namedQueries.getQuery(name),
- getCountQuery(method, namedQueries, em), evaluationContextProvider, getQueryRewriterSupplier());
+ getCountQuery(method, namedQueries, em), queryRewriter, evaluationContextProvider);
}
RepositoryQuery query = NamedQuery.lookupFrom(method, em);
@@ -240,12 +242,13 @@ public final class JpaQueryLookupStrategy {
}
@Override
- protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries) {
+ protected RepositoryQuery resolveQuery(JpaQueryMethod method, QueryRewriter queryRewriter, EntityManager em,
+ NamedQueries namedQueries) {
try {
- return lookupStrategy.resolveQuery(method, em, namedQueries);
+ return lookupStrategy.resolveQuery(method, queryRewriter, em, namedQueries);
} catch (IllegalStateException e) {
- return createStrategy.resolveQuery(method, em, namedQueries);
+ return createStrategy.resolveQuery(method, queryRewriter, em, namedQueries);
}
}
}
@@ -270,7 +273,8 @@ public final class JpaQueryLookupStrategy {
case CREATE:
return new CreateQueryLookupStrategy(em, queryMethodFactory, queryRewriterProvider, escape);
case USE_DECLARED_QUERY:
- return new DeclaredQueryLookupStrategy(em, queryMethodFactory, evaluationContextProvider, queryRewriterProvider);
+ return new DeclaredQueryLookupStrategy(em, queryMethodFactory, evaluationContextProvider,
+ queryRewriterProvider);
case CREATE_IF_NOT_FOUND:
return new CreateIfNotFoundQueryLookupStrategy(em, queryMethodFactory,
new CreateQueryLookupStrategy(em, queryMethodFactory, queryRewriterProvider, escape),
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java
index 88e085527..e3138c5bd 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java
@@ -266,7 +266,7 @@ public class JpaQueryMethod extends QueryMethod {
* @return
*/
@Nullable
- String getAnnotatedQuery() {
+ public String getAnnotatedQuery() {
String query = getAnnotationValue("value", String.class);
return StringUtils.hasText(query) ? query : null;
@@ -287,7 +287,7 @@ public class JpaQueryMethod extends QueryMethod {
* @throws IllegalStateException if no {@link Query} annotation is present or the query is empty.
* @since 2.0
*/
- String getRequiredAnnotatedQuery() throws IllegalStateException {
+ public String getRequiredAnnotatedQuery() throws IllegalStateException {
String query = getAnnotatedQuery();
@@ -305,7 +305,7 @@ public class JpaQueryMethod extends QueryMethod {
* @return
*/
@Nullable
- String getCountQuery() {
+ public String getCountQuery() {
String countQuery = getAnnotationValue("countQuery", String.class);
return StringUtils.hasText(countQuery) ? countQuery : null;
@@ -438,8 +438,7 @@ public class JpaQueryMethod extends QueryMethod {
* @return type of the {@link QueryRewriter}
* @since 3.0
*/
- @Nullable
- Class extends QueryRewriter> getQueryRewriter() {
+ public Class extends QueryRewriter> getQueryRewriter() {
return getMergedOrDefaultAnnotationValue("queryRewriter", Query.class, Class.class);
}
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NativeJpaQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NativeJpaQuery.java
index c517ff0ae..205e7d1f2 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NativeJpaQuery.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NativeJpaQuery.java
@@ -21,6 +21,7 @@ import jakarta.persistence.Tuple;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.repository.QueryRewriter;
import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.RepositoryQuery;
@@ -48,13 +49,13 @@ final class NativeJpaQuery extends AbstractStringBasedJpaQuery {
* @param em must not be {@literal null}.
* @param queryString must not be {@literal null} or empty.
* @param countQueryString must not be {@literal null} or empty.
- * @param evaluationContextProvider
+ * @param rewriter the query rewriter to use.
*/
public NativeJpaQuery(JpaQueryMethod method, EntityManager em, String queryString, @Nullable String countQueryString,
- QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser,
- QueryRewriterProvider queryRewriterProvider) {
+ QueryRewriter rewriter, QueryMethodEvaluationContextProvider evaluationContextProvider,
+ SpelExpressionParser parser) {
- super(method, em, queryString, countQueryString, evaluationContextProvider, parser, queryRewriterProvider);
+ super(method, em, queryString, countQueryString, rewriter, evaluationContextProvider, parser);
Parameters, ?> parameters = method.getParameters();
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRewriterNoopProvider.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRewriterNoopProvider.java
deleted file mode 100644
index 094e377cd..000000000
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRewriterNoopProvider.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2008-2022 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.query;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.data.jpa.repository.QueryRewriter;
-
-/**
- * {@link QueryRewriterProvider} that does nothing.
- *
- * @author Greg Turnquist
- * @since 3.0
- */
-public class QueryRewriterNoopProvider extends QueryRewriterProvider {
-
- private static final Log LOGGER = LogFactory.getLog(QueryRewriterNoopProvider.class);
-
- /**
- * Returns {@literal null}, signaling there is no rewriting.
- *
- * @param queryRewriter class definition to find in the context
- * @return {@literal null} since this doesn't actually rewrite anything.
- */
- @Override
- public QueryRewriter extractQueryRewriterBean(Class extends QueryRewriter> queryRewriter) {
-
- LOGGER.warn("You have NOT configured JpaRepositoryFactory with a QueryRewriterProvider!");
-
- return null;
- }
-}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRewriterProvider.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRewriterProvider.java
index ba8071e5c..ed955d9d5 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRewriterProvider.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRewriterProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2022 the original author or authors.
+ * Copyright 2022 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.
@@ -15,57 +15,45 @@
*/
package org.springframework.data.jpa.repository.query;
-import java.util.function.Supplier;
-
+import org.springframework.beans.BeanUtils;
import org.springframework.data.jpa.repository.QueryRewriter;
-import org.springframework.lang.Nullable;
/**
- * Provide a {@link QueryRewriter} based upon the {@link JpaQueryMethod} and the surrounding context (Spring, CDI, etc.)
+ * Provide a {@link QueryRewriter} based upon the {@link JpaQueryMethod}. {@code QueryRewriter} instances may be
+ * contextual or plain objects that are not attached to a bean factory or CDI context.
*
* @author Greg Turnquist
+ * @author Mark Paluch
* @since 3.0
+ * @see QueryRewriter
*/
-public abstract class QueryRewriterProvider {
+public interface QueryRewriterProvider {
/**
- * Using a {@link JpaQueryMethod}, extract a potential {@link QueryRewriter}. Wrap all this in a {@link Supplier} to
- * defer the lookup until needed.
- *
- * @param method - JpaQueryMethod
- * @return a {@link Supplier}-wrapped callback to fetch the {@link QueryRewriter}
+ * Return a simple {@code QueryRewriterProvider} that uses
+ * {@link org.springframework.beans.BeanUtils#instantiateClass(Class)} to obtain a {@link QueryRewriter} instance.
+ *
+ * @return a simple {@link QueryRewriterProvider}.
*/
- public Supplier of(JpaQueryMethod method) {
- return () -> findQueryRewriter(method);
+ static QueryRewriterProvider simple() {
+
+ return method -> {
+
+ Class extends QueryRewriter> queryRewriter = method.getQueryRewriter();
+
+ if (queryRewriter == QueryRewriter.IdentityQueryRewriter.class) {
+ return QueryRewriter.IdentityQueryRewriter.INSTANCE;
+ }
+
+ return BeanUtils.instantiateClass(queryRewriter);
+ };
}
/**
- * Using the {@link org.springframework.data.jpa.repository.QueryRewrite} annotation, look for a {@link QueryRewriter}
- * and instantiate one. NOTE: If its {@link QueryRewriter.NoopQueryRewriter}, it will just return {@literal null} and
- * NOT do any rewrite operations.
+ * Obtain an instance of {@link QueryRewriter} for a {@link JpaQueryMethod}.
*
- * @param method - {@link JpaQueryMethod} that has the annotation details
- * @return a {@link QueryRewriter for the method or {@code null}
+ * @param method the underlying JPA query method.
+ * @return a Java bean that implements {@link QueryRewriter}.
*/
- @Nullable
- private QueryRewriter findQueryRewriter(JpaQueryMethod method) {
-
- Class extends QueryRewriter> queryRewriter = method.getQueryRewriter();
-
- if (queryRewriter == null || queryRewriter == QueryRewriter.NoopQueryRewriter.class) {
- return null;
- }
-
- return extractQueryRewriterBean(queryRewriter);
- }
-
- /**
- * Extract an instance of {@link QueryRewriter} from the context. Implementations choose what context means, whether
- * that is Spring, CDI, or whatever.
- *
- * @param queryRewriter
- * @return a Java bean that implements {@link QueryRewriter}. {@literal null} is valid if no bean is found.
- */
- @Nullable
- protected abstract QueryRewriter extractQueryRewriterBean(Class extends QueryRewriter> queryRewriter);
+ QueryRewriter getQueryRewriter(JpaQueryMethod method);
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java
index 6e48f10bd..1e765db9c 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java
@@ -18,6 +18,7 @@ package org.springframework.data.jpa.repository.query;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
+import org.springframework.data.jpa.repository.QueryRewriter;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.expression.spel.standard.SpelExpressionParser;
@@ -41,14 +42,13 @@ final class SimpleJpaQuery extends AbstractStringBasedJpaQuery {
* @param method must not be {@literal null}
* @param em must not be {@literal null}
* @param countQueryString
+ * @param queryRewriter must not be {@literal null}
* @param evaluationContextProvider must not be {@literal null}
* @param parser must not be {@literal null}
*/
public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, @Nullable String countQueryString,
- QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser,
- QueryRewriterProvider queryRewriterProvider) {
- this(method, em, method.getRequiredAnnotatedQuery(), countQueryString, evaluationContextProvider, parser,
- queryRewriterProvider);
+ QueryRewriter queryRewriter, QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) {
+ this(method, em, method.getRequiredAnnotatedQuery(), countQueryString, queryRewriter, evaluationContextProvider, parser);
}
/**
@@ -58,14 +58,14 @@ final class SimpleJpaQuery extends AbstractStringBasedJpaQuery {
* @param em must not be {@literal null}
* @param queryString must not be {@literal null} or empty
* @param countQueryString
+ * @param queryRewriter
* @param evaluationContextProvider must not be {@literal null}
* @param parser must not be {@literal null}
*/
- public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, String queryString, @Nullable String countQueryString,
- QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser,
- QueryRewriterProvider queryRewriterProvider) {
+ public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, String queryString, @Nullable String countQueryString, QueryRewriter queryRewriter,
+ QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) {
- super(method, em, queryString, countQueryString, evaluationContextProvider, parser, queryRewriterProvider);
+ super(method, em, queryString, countQueryString, queryRewriter, evaluationContextProvider, parser);
validateQuery(getQuery().getQueryString(), "Validation failed for query for method %s!", method);
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java
index 367d0bf92..46f8624c7 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java
@@ -27,6 +27,8 @@ import java.util.stream.Stream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.dao.InvalidDataAccessApiUsageException;
@@ -34,7 +36,15 @@ import org.springframework.data.jpa.projection.CollectionAwareProjectionFactory;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.query.*;
+import org.springframework.data.jpa.repository.query.AbstractJpaQuery;
+import org.springframework.data.jpa.repository.query.BeanFactoryQueryRewriterProvider;
+import org.springframework.data.jpa.repository.query.DefaultJpaQueryMethodFactory;
+import org.springframework.data.jpa.repository.query.EscapeCharacter;
+import org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy;
+import org.springframework.data.jpa.repository.query.JpaQueryMethod;
+import org.springframework.data.jpa.repository.query.JpaQueryMethodFactory;
+import org.springframework.data.jpa.repository.query.Procedure;
+import org.springframework.data.jpa.repository.query.QueryRewriterProvider;
import org.springframework.data.jpa.util.JpaMetamodel;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.querydsl.EntityPathResolver;
@@ -93,12 +103,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
this.crudMethodMetadataPostProcessor = new CrudMethodMetadataPostProcessor();
this.entityPathResolver = SimpleEntityPathResolver.INSTANCE;
this.queryMethodFactory = new DefaultJpaQueryMethodFactory(extractor);
-
- /**
- * Default to {@link QueryRewriterNoopProvider}. If there is a {@link BeanFactory} or {@link BeanManager}, this will
- * result in later overriding this with the proper version.
- */
- this.queryRewriterProvider = new QueryRewriterNoopProvider();
+ this.queryRewriterProvider = QueryRewriterProvider.simple();
addRepositoryProxyPostProcessor(crudMethodMetadataPostProcessor);
addRepositoryProxyPostProcessor((factory, repositoryInformation) -> {
@@ -122,8 +127,8 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
/**
* If a {@link BeanFactory} is being set, this is clearly in a Spring context, and so we can capture the
- * {@link QueryRewriterProvider} being a {@link QueryRewriterBeanFactoryProvider}.
- *
+ * {@link QueryRewriterProvider} being a {@link BeanFactoryQueryRewriterProvider}.
+ *
* @param beanFactory
* @throws BeansException
*/
@@ -134,7 +139,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
Assert.notNull(beanFactory, "BeanFactory must not be null!");
- setQueryRewriterProvider(new QueryRewriterBeanFactoryProvider(beanFactory));
+ setQueryRewriterProvider(new BeanFactoryQueryRewriterProvider(beanFactory));
}
/**
@@ -171,9 +176,11 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
}
/**
- * Configures the {@link QueryRewriterProvider} to be used. Defaults to {@link QueryRewriterNoopProvider}.
+ * Configures the {@link QueryRewriterProvider} to be used. Defaults to instantiate query rewriters through
+ * {@link BeanUtils#instantiateClass(Class)}.
*
- * @param queryRewriterProvider must not be {@literal null}
+ * @param queryRewriterProvider must not be {@literal null}.
+ * @since 3.0
*/
public void setQueryRewriterProvider(QueryRewriterProvider queryRewriterProvider) {
@@ -254,7 +261,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
*
* @param metadata repository metadata.
* @param entityManager the entity manager.
- * @param resolver resolver to translate an plain domain class into a {@link EntityPath}.
+ * @param resolver resolver to translate a plain domain class into a {@link EntityPath}.
* @param crudMethodMetadata metadata about the invoked CRUD methods.
* @return
* @since 2.5.1
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/JpaQueryRewriterWithCdiIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/JpaQueryRewriterWithCdiIntegrationTests.java
index aae03b374..3077542d7 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/JpaQueryRewriterWithCdiIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/JpaQueryRewriterWithCdiIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2022 the original author or authors.
+ * Copyright 2022 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.
@@ -43,7 +43,7 @@ import org.springframework.data.repository.cdi.Eager;
/**
* Unit tests for repository with {@link Query} and {@link QueryRewrite} in a CDI environment.
- *
+ *
* @author Greg Turnquist
*/
public class JpaQueryRewriterWithCdiIntegrationTests {
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryIntegrationTests.java
index 09f7789b9..33abbeebb 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryIntegrationTests.java
@@ -34,6 +34,7 @@ import org.springframework.data.jpa.domain.sample.Role;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.jpa.repository.QueryRewriter;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
@@ -66,9 +67,8 @@ public class AbstractStringBasedJpaQueryIntegrationTests {
when(mock.getMetamodel()).thenReturn(em.getMetamodel());
JpaQueryMethod method = getMethod("findRolesByEmailAddress", String.class);
- AbstractStringBasedJpaQuery jpaQuery = new SimpleJpaQuery(method, mock, null,
- QueryMethodEvaluationContextProvider.DEFAULT, new SpelExpressionParser(),
- new QueryRewriterBeanFactoryProvider(beanFactory));
+ AbstractStringBasedJpaQuery jpaQuery = new SimpleJpaQuery(method, mock, null, QueryRewriter.IdentityQueryRewriter.INSTANCE,
+ QueryMethodEvaluationContextProvider.DEFAULT, new SpelExpressionParser());
jpaQuery.createJpaQuery(method.getAnnotatedQuery(), Sort.unsorted(), null,
method.getResultProcessor().getReturnedType());
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java
index ed71fc826..0ba5d98e9 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java
@@ -89,7 +89,7 @@ public class JpaQueryLookupStrategyUnitTests {
void invalidAnnotatedQueryCausesException() throws Exception {
QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND,
- EVALUATION_CONTEXT_PROVIDER, new QueryRewriterBeanFactoryProvider(beanFactory), EscapeCharacter.DEFAULT);
+ EVALUATION_CONTEXT_PROVIDER, new BeanFactoryQueryRewriterProvider(beanFactory), EscapeCharacter.DEFAULT);
Method method = UserRepository.class.getMethod("findByFoo", String.class);
RepositoryMetadata metadata = new DefaultRepositoryMetadata(UserRepository.class);
@@ -105,7 +105,7 @@ public class JpaQueryLookupStrategyUnitTests {
void sholdThrowMorePreciseExceptionIfTryingToUsePaginationInNativeQueries() throws Exception {
QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND,
- EVALUATION_CONTEXT_PROVIDER, new QueryRewriterBeanFactoryProvider(beanFactory), EscapeCharacter.DEFAULT);
+ EVALUATION_CONTEXT_PROVIDER, new BeanFactoryQueryRewriterProvider(beanFactory), EscapeCharacter.DEFAULT);
Method method = UserRepository.class.getMethod("findByInvalidNativeQuery", String.class, Sort.class);
RepositoryMetadata metadata = new DefaultRepositoryMetadata(UserRepository.class);
@@ -119,7 +119,7 @@ public class JpaQueryLookupStrategyUnitTests {
void considersNamedCountQuery() throws Exception {
QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND,
- EVALUATION_CONTEXT_PROVIDER, new QueryRewriterBeanFactoryProvider(beanFactory), EscapeCharacter.DEFAULT);
+ EVALUATION_CONTEXT_PROVIDER, new BeanFactoryQueryRewriterProvider(beanFactory), EscapeCharacter.DEFAULT);
when(namedQueries.hasQuery("foo.count")).thenReturn(true);
when(namedQueries.getQuery("foo.count")).thenReturn("foo count");
@@ -141,7 +141,7 @@ public class JpaQueryLookupStrategyUnitTests {
void considersNamedCountOnStringQueryQuery() throws Exception {
QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND,
- EVALUATION_CONTEXT_PROVIDER, new QueryRewriterBeanFactoryProvider(beanFactory), EscapeCharacter.DEFAULT);
+ EVALUATION_CONTEXT_PROVIDER, new BeanFactoryQueryRewriterProvider(beanFactory), EscapeCharacter.DEFAULT);
when(namedQueries.hasQuery("foo.count")).thenReturn(true);
when(namedQueries.getQuery("foo.count")).thenReturn("foo count");
@@ -160,7 +160,7 @@ public class JpaQueryLookupStrategyUnitTests {
void prefersDeclaredQuery() throws Exception {
QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND,
- EVALUATION_CONTEXT_PROVIDER, new QueryRewriterBeanFactoryProvider(beanFactory), EscapeCharacter.DEFAULT);
+ EVALUATION_CONTEXT_PROVIDER, new BeanFactoryQueryRewriterProvider(beanFactory), EscapeCharacter.DEFAULT);
Method method = UserRepository.class.getMethod("annotatedQueryWithQueryAndQueryName");
RepositoryMetadata metadata = new DefaultRepositoryMetadata(UserRepository.class);
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryRewriteIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryRewriteIntegrationTests.java
index f11d645fc..61d0db240 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryRewriteIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryRewriteIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2022 the original author or authors.
+ * Copyright 2022 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.
@@ -43,7 +43,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
/**
* Unit tests for repository with {@link Query} and {@link QueryRewrite}.
- *
+ *
* @author Greg Turnquist
*/
@ExtendWith(SpringExtension.class)
@@ -64,7 +64,7 @@ public class JpaQueryRewriteIntegrationTests {
}
@Test
- void nativeQueryShouldHandleRewrites() throws NoSuchMethodException {
+ void nativeQueryShouldHandleRewrites() {
repository.findByNativeQuery("Matthews");
@@ -75,7 +75,7 @@ public class JpaQueryRewriteIntegrationTests {
}
@Test
- void nonNativeQueryShouldHandleRewrites() throws NoSuchMethodException {
+ void nonNativeQueryShouldHandleRewrites() {
repository.findByNonNativeQuery("Matthews");
@@ -86,7 +86,7 @@ public class JpaQueryRewriteIntegrationTests {
}
@Test
- void nonNativeQueryWithSortShouldHandleRewrites() throws NoSuchMethodException {
+ void nonNativeQueryWithSortShouldHandleRewrites() {
repository.findByNonNativeSortedQuery("Matthews", Sort.by("lastname"));
@@ -108,7 +108,7 @@ public class JpaQueryRewriteIntegrationTests {
}
@Test
- void nonNativeQueryWithPageableShouldHandleRewrites() throws NoSuchMethodException {
+ void nonNativeQueryWithPageableShouldHandleRewrites() {
repository.findByNonNativePagedQuery("Matthews", PageRequest.of(2, 1));
@@ -119,7 +119,7 @@ public class JpaQueryRewriteIntegrationTests {
}
@Test
- void nativeQueryWithNoRewriteAnnotationShouldNotDoRewrites() throws NoSuchMethodException {
+ void nativeQueryWithNoRewriteAnnotationShouldNotDoRewrites() {
repository.findByNativeQueryWithNoRewrite("Matthews");
@@ -127,7 +127,7 @@ public class JpaQueryRewriteIntegrationTests {
}
@Test
- void nonNativeQueryWithNoRewriteAnnotationShouldNotDoRewrites() throws NoSuchMethodException {
+ void nonNativeQueryWithNoRewriteAnnotationShouldNotDoRewrites() {
repository.findByNonNativeQueryWithNoRewrite("Matthews");
@@ -135,7 +135,7 @@ public class JpaQueryRewriteIntegrationTests {
}
@Test
- void nativeQueryShouldHandleRewritesUsingRepositoryRewriter() throws NoSuchMethodException {
+ void nativeQueryShouldHandleRewritesUsingRepositoryRewriter() {
repository.findByNativeQueryUsingRepository("Matthews");
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java
index d394bfc5c..8ebb5a4e8 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java
@@ -37,7 +37,7 @@ import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
-import org.springframework.beans.factory.BeanFactory;
+
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
@@ -45,6 +45,7 @@ import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.jpa.repository.QueryRewriter;
import org.springframework.data.jpa.repository.sample.UserRepository;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
@@ -82,7 +83,6 @@ class SimpleJpaQueryUnitTests {
@Mock RepositoryMetadata metadata;
@Mock ParameterBinder binder;
@Mock Metamodel metamodel;
- @Mock BeanFactory beanFactory;
private ProjectionFactory factory = new SpelAwareProxyProjectionFactory();
@@ -113,8 +113,8 @@ class SimpleJpaQueryUnitTests {
extractor);
when(em.createQuery("foo", Long.class)).thenReturn(typedQuery);
- SimpleJpaQuery jpaQuery = new SimpleJpaQuery(method, em, "select u from User u", null, EVALUATION_CONTEXT_PROVIDER,
- PARSER, new QueryRewriterBeanFactoryProvider(beanFactory));
+ SimpleJpaQuery jpaQuery = new SimpleJpaQuery(method, em, "select u from User u", null,
+ QueryRewriter.IdentityQueryRewriter.INSTANCE, EVALUATION_CONTEXT_PROVIDER, PARSER);
assertThat(jpaQuery.createCountQuery(new JpaParametersParameterAccessor(method.getParameters(), new Object[] {})))
.isEqualTo(typedQuery);
@@ -129,7 +129,7 @@ class SimpleJpaQueryUnitTests {
JpaQueryMethod queryMethod = new JpaQueryMethod(method, metadata, factory, extractor);
AbstractJpaQuery jpaQuery = new SimpleJpaQuery(queryMethod, em, "select u from User u", null,
- EVALUATION_CONTEXT_PROVIDER, PARSER, new QueryRewriterBeanFactoryProvider(beanFactory));
+ QueryRewriter.IdentityQueryRewriter.INSTANCE, EVALUATION_CONTEXT_PROVIDER, PARSER);
jpaQuery.createCountQuery(
new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[] { PageRequest.of(1, 10) }));
@@ -144,7 +144,8 @@ class SimpleJpaQueryUnitTests {
Method method = SampleRepository.class.getMethod("findNativeByLastname", String.class);
JpaQueryMethod queryMethod = new JpaQueryMethod(method, metadata, factory, extractor);
AbstractJpaQuery jpaQuery = JpaQueryFactory.INSTANCE.fromMethodWithQueryString(queryMethod, em,
- queryMethod.getAnnotatedQuery(), null, EVALUATION_CONTEXT_PROVIDER, new QueryRewriterBeanFactoryProvider(beanFactory));
+ queryMethod.getAnnotatedQuery(), null, QueryRewriter.IdentityQueryRewriter.INSTANCE,
+ EVALUATION_CONTEXT_PROVIDER);
assertThat(jpaQuery instanceof NativeJpaQuery).isTrue();
@@ -247,7 +248,8 @@ class SimpleJpaQueryUnitTests {
JpaQueryMethod queryMethod = new JpaQueryMethod(method, metadata, factory, extractor);
AbstractJpaQuery jpaQuery = new SimpleJpaQuery(queryMethod, em, "select u from User u",
- "select count(u.id) from #{#entityName} u", EVALUATION_CONTEXT_PROVIDER, PARSER, new QueryRewriterBeanFactoryProvider(beanFactory));
+ "select count(u.id) from #{#entityName} u", QueryRewriter.IdentityQueryRewriter.INSTANCE,
+ EVALUATION_CONTEXT_PROVIDER, PARSER);
jpaQuery.createCountQuery(
new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[] { PageRequest.of(1, 10) }));
@@ -259,7 +261,7 @@ class SimpleJpaQueryUnitTests {
JpaQueryMethod queryMethod = new JpaQueryMethod(method, metadata, factory, extractor);
return JpaQueryFactory.INSTANCE.fromMethodWithQueryString(queryMethod, em, queryMethod.getAnnotatedQuery(), null,
- EVALUATION_CONTEXT_PROVIDER, new QueryRewriterBeanFactoryProvider(beanFactory));
+ QueryRewriter.IdentityQueryRewriter.INSTANCE, EVALUATION_CONTEXT_PROVIDER);
}
interface SampleRepository {