setters = new ArrayList<>(parameterBindings.size());
for (ParameterBinding parameterBinding : parameterBindings) {
- setters.add(createQueryParameterSetter(parameterBinding, strategies, declaredQuery));
+ setters.add(createQueryParameterSetter(parameterBinding, strategies, query));
}
return setters;
}
private static QueryParameterSetter createQueryParameterSetter(ParameterBinding binding,
- QueryParameterSetterFactory[] strategies, DeclaredQuery declaredQuery) {
+ QueryParameterSetterFactory[] strategies, IntrospectedQuery query) {
for (QueryParameterSetterFactory strategy : strategies) {
- QueryParameterSetter setter = strategy.create(binding);
+ QueryParameterSetter setter = strategy.create(binding, query);
if (setter != null) {
return setter;
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancer.java
index 88d4716d88..b6e0f7c06a 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancer.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancer.java
@@ -65,7 +65,6 @@ public interface QueryEnhancer {
*
* @return non-null {@link DeclaredQuery} that wraps the query.
*/
- @Deprecated(forRemoval = true)
DeclaredQuery getQuery();
/**
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactories.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactories.java
new file mode 100644
index 0000000000..b88a6953f0
--- /dev/null
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactories.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2024 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.provider.PersistenceProvider;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Pre-defined QueryEnhancerFactories to be used for query enhancement.
+ *
+ * @author Mark Paluch
+ */
+public class QueryEnhancerFactories {
+
+ private static final Log LOG = LogFactory.getLog(QueryEnhancerFactory.class);
+
+ static final boolean jSqlParserPresent = ClassUtils.isPresent("net.sf.jsqlparser.parser.JSqlParser",
+ QueryEnhancerFactory.class.getClassLoader());
+
+ static {
+
+ if (jSqlParserPresent) {
+ LOG.info("JSqlParser is in classpath; If applicable, JSqlParser will be used");
+ }
+
+ if (PersistenceProvider.ECLIPSELINK.isPresent()) {
+ LOG.info("EclipseLink is in classpath; If applicable, EQL parser will be used.");
+ }
+
+ if (PersistenceProvider.HIBERNATE.isPresent()) {
+ LOG.info("Hibernate is in classpath; If applicable, HQL parser will be used.");
+ }
+ }
+
+ enum BuiltinQueryEnhancerFactories implements QueryEnhancerFactory {
+
+ FALLBACK {
+ @Override
+ public boolean supports(DeclaredQuery query) {
+ return true;
+ }
+
+ @Override
+ public QueryEnhancer create(DeclaredQuery query) {
+ return new DefaultQueryEnhancer(query);
+ }
+ },
+
+ JSQLPARSER {
+ @Override
+ public boolean supports(DeclaredQuery query) {
+ return query.isNativeQuery();
+ }
+
+ @Override
+ public QueryEnhancer create(DeclaredQuery query) {
+ if (jSqlParserPresent) {
+ return new JSqlParserQueryEnhancer(query);
+ }
+
+ throw new IllegalStateException("JSQLParser is not available on the class path");
+ }
+ },
+
+ HQL {
+ @Override
+ public boolean supports(DeclaredQuery query) {
+ return !query.isNativeQuery();
+ }
+
+ @Override
+ public QueryEnhancer create(DeclaredQuery query) {
+ return JpaQueryEnhancer.forHql(query.getQueryString());
+ }
+ },
+ EQL {
+ @Override
+ public boolean supports(DeclaredQuery query) {
+ return !query.isNativeQuery();
+ }
+
+ @Override
+ public QueryEnhancer create(DeclaredQuery query) {
+ return JpaQueryEnhancer.forEql(query.getQueryString());
+ }
+ },
+ JPQL {
+ @Override
+ public boolean supports(DeclaredQuery query) {
+ return !query.isNativeQuery();
+ }
+
+ @Override
+ public QueryEnhancer create(DeclaredQuery query) {
+ return JpaQueryEnhancer.forJpql(query.getQueryString());
+ }
+ }
+ }
+
+ /**
+ * Returns the default fallback {@link QueryEnhancerFactory} using regex-based detection. This factory supports only
+ * simple SQL queries.
+ *
+ * @return fallback {@link QueryEnhancerFactory} using regex-based detection.
+ */
+ public static QueryEnhancerFactory fallback() {
+ return BuiltinQueryEnhancerFactories.FALLBACK;
+ }
+
+ /**
+ * Returns a {@link QueryEnhancerFactory} that uses JSqlParser
+ * if it is available from the class path.
+ *
+ * @return a {@link QueryEnhancerFactory} that uses JSqlParser.
+ * @throws IllegalStateException if JSQLParser is not on the class path.
+ */
+ public static QueryEnhancerFactory jsqlparser() {
+
+ if (!jSqlParserPresent) {
+ throw new IllegalStateException("JSQLParser is not available on the class path");
+ }
+
+ return BuiltinQueryEnhancerFactories.JSQLPARSER;
+ }
+
+ /**
+ * Returns a {@link QueryEnhancerFactory} using HQL (Hibernate Query Language) parser.
+ *
+ * @return a {@link QueryEnhancerFactory} using HQL (Hibernate Query Language) parser.
+ */
+ public static QueryEnhancerFactory hql() {
+ return BuiltinQueryEnhancerFactories.HQL;
+ }
+
+ /**
+ * Returns a {@link QueryEnhancerFactory} using EQL (EclipseLink Query Language) parser.
+ *
+ * @return a {@link QueryEnhancerFactory} using EQL (EclipseLink Query Language) parser.
+ */
+ public static QueryEnhancerFactory eql() {
+ return BuiltinQueryEnhancerFactories.EQL;
+ }
+
+ /**
+ * Returns a {@link QueryEnhancerFactory} using JPQL (Jakarta Persistence Query Language) parser as per the JPA spec.
+ *
+ * @return a {@link QueryEnhancerFactory} using JPQL (Jakarta Persistence Query Language) parser as per the JPA spec.
+ */
+ public static QueryEnhancerFactory jpql() {
+ return BuiltinQueryEnhancerFactories.JPQL;
+ }
+}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java
index 5a2853cb1a..a3e7b5f06d 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java
@@ -15,133 +15,41 @@
*/
package org.springframework.data.jpa.repository.query;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.core.SpringProperties;
-import org.springframework.data.jpa.provider.PersistenceProvider;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.ObjectUtils;
-import org.springframework.util.StringUtils;
-
/**
- * Encapsulates different strategies for the creation of a {@link QueryEnhancer} from a {@link DeclaredQuery}.
+ * Encapsulates different strategies for the creation of a {@link QueryEnhancer} from a {@link IntrospectedQuery}.
*
* @author Diego Krupitza
* @author Greg Turnquist
* @author Mark Paluch
* @author Christoph Strobl
- * @since 2.7.0
+ * @since 2.7
*/
-public final class QueryEnhancerFactory {
-
- private static final Log LOG = LogFactory.getLog(QueryEnhancerFactory.class);
- private static final NativeQueryEnhancer NATIVE_QUERY_ENHANCER;
-
- static {
-
- NATIVE_QUERY_ENHANCER = NativeQueryEnhancer.select();
-
- if (PersistenceProvider.ECLIPSELINK.isPresent()) {
- LOG.info("EclipseLink is in classpath; If applicable, EQL parser will be used.");
- }
-
- if (PersistenceProvider.HIBERNATE.isPresent()) {
- LOG.info("Hibernate is in classpath; If applicable, HQL parser will be used.");
- }
- }
-
- private QueryEnhancerFactory() {}
+public interface QueryEnhancerFactory {
/**
- * Creates a new {@link QueryEnhancer} for the given {@link DeclaredQuery}.
+ * Returns whether this QueryEnhancerFactory supports the given {@link DeclaredQuery}.
*
- * @param query must not be {@literal null}.
- * @return an implementation of {@link QueryEnhancer} that suits the query the most
+ * @param query the query to be enhanced and introspected.
+ * @return {@code true} if this QueryEnhancer supports the given query; {@code false} otherwise.
*/
- public static QueryEnhancer forQuery(DeclaredQuery query) {
-
- if (query.isNativeQuery()) {
- return getNativeQueryEnhancer(query);
- }
-
- if (PersistenceProvider.HIBERNATE.isPresent()) {
- return JpaQueryEnhancer.forHql(query);
- } else if (PersistenceProvider.ECLIPSELINK.isPresent()) {
- return JpaQueryEnhancer.forEql(query);
- } else {
- return JpaQueryEnhancer.forJpql(query);
- }
- }
+ boolean supports(DeclaredQuery query);
/**
- * Get the native query enhancer for the given {@link DeclaredQuery query} based on {@link #NATIVE_QUERY_ENHANCER}.
+ * Creates a new {@link QueryEnhancer} for the given query.
*
- * @param query the declared query.
- * @return new instance of {@link QueryEnhancer}.
+ * @param query the query to be enhanced and introspected.
+ * @return
*/
- private static QueryEnhancer getNativeQueryEnhancer(DeclaredQuery query) {
-
- if (NATIVE_QUERY_ENHANCER.equals(NativeQueryEnhancer.JSQLPARSER)) {
- return new JSqlParserQueryEnhancer(query);
- }
-
- return new DefaultQueryEnhancer(query);
- }
+ QueryEnhancer create(DeclaredQuery query);
/**
- * Possible choices for the {@link #NATIVE_PARSER_PROPERTY}. Resolve the parser through {@link #select()}.
+ * Creates a new {@link QueryEnhancerFactory} for the given {@link DeclaredQuery}.
*
- * @since 3.3.5
+ * @param query must not be {@literal null}.
+ * @return an implementation of {@link QueryEnhancer} that suits the query the most
*/
- enum NativeQueryEnhancer {
-
- AUTO, REGEX, JSQLPARSER;
-
- static final String NATIVE_PARSER_PROPERTY = "spring.data.jpa.query.native.parser";
-
- static final boolean JSQLPARSER_PRESENT = ClassUtils.isPresent("net.sf.jsqlparser.parser.JSqlParser", null);
-
- /**
- * @return the current selection considering classpath availability and user selection via
- * {@link #NATIVE_PARSER_PROPERTY}.
- */
- static NativeQueryEnhancer select() {
-
- NativeQueryEnhancer selected = resolve();
-
- if (selected.equals(NativeQueryEnhancer.JSQLPARSER)) {
- LOG.info("User choice: Using JSqlParser");
- return NativeQueryEnhancer.JSQLPARSER;
- }
-
- if (selected.equals(NativeQueryEnhancer.REGEX)) {
- LOG.info("Using Regex QueryEnhancer");
- return NativeQueryEnhancer.REGEX;
- }
-
- if (!JSQLPARSER_PRESENT) {
- return NativeQueryEnhancer.REGEX;
- }
-
- LOG.info("JSqlParser is in classpath; If applicable, JSqlParser will be used.");
- return NativeQueryEnhancer.JSQLPARSER;
- }
-
- /**
- * Resolve {@link NativeQueryEnhancer} from {@link SpringProperties}.
- *
- * @return the {@link NativeQueryEnhancer} constant.
- */
- private static NativeQueryEnhancer resolve() {
-
- String name = SpringProperties.getProperty(NATIVE_PARSER_PROPERTY);
-
- if (StringUtils.hasText(name)) {
- return ObjectUtils.caseInsensitiveValueOf(NativeQueryEnhancer.values(), name);
- }
-
- return AUTO;
- }
+ static QueryEnhancerFactory forQuery(DeclaredQuery query) {
+ return QueryEnhancerSelector.DEFAULT_SELECTOR.select(query);
}
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerSelector.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerSelector.java
new file mode 100644
index 0000000000..75bee83f1d
--- /dev/null
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerSelector.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2024 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.springframework.data.jpa.provider.PersistenceProvider;
+
+/**
+ * Interface declaring a strategy to select a {@link QueryEnhancer} for a given {@link DeclaredQuery query}.
+ *
+ * Enhancers are selected when introspecting a query to determine their selection, joins, aliases and other information
+ * so that query methods can derive count queries, apply sorting and perform other transformations.
+ *
+ * @author Mark Paluch
+ */
+public interface QueryEnhancerSelector {
+
+ /**
+ * Default selector strategy.
+ */
+ QueryEnhancerSelector DEFAULT_SELECTOR = new DefaultQueryEnhancerSelector();
+
+ /**
+ * Select a {@link QueryEnhancer} for a {@link DeclaredQuery query}.
+ *
+ * @param query
+ * @return
+ */
+ QueryEnhancerFactory select(DeclaredQuery query);
+
+ /**
+ * Default {@link QueryEnhancerSelector} implementation using class-path information to determine enhancer
+ * availability. Subclasses may provide a different configuration by using the protected constructor.
+ */
+ class DefaultQueryEnhancerSelector implements QueryEnhancerSelector {
+
+ protected static QueryEnhancerFactory DEFAULT_NATIVE;
+ protected static QueryEnhancerFactory DEFAULT_JPQL;
+
+ static {
+
+ DEFAULT_NATIVE = QueryEnhancerFactories.jSqlParserPresent ? QueryEnhancerFactories.jsqlparser()
+ : QueryEnhancerFactories.fallback();
+
+ if (PersistenceProvider.HIBERNATE.isPresent()) {
+ DEFAULT_JPQL = QueryEnhancerFactories.hql();
+ } else if (PersistenceProvider.ECLIPSELINK.isPresent()) {
+ DEFAULT_JPQL = QueryEnhancerFactories.eql();
+ } else {
+ DEFAULT_JPQL = QueryEnhancerFactories.jpql();
+ }
+ }
+
+ private final QueryEnhancerFactory nativeQuery;
+ private final QueryEnhancerFactory jpql;
+
+ public DefaultQueryEnhancerSelector() {
+ this(DEFAULT_NATIVE, DEFAULT_JPQL);
+ }
+
+ protected DefaultQueryEnhancerSelector(QueryEnhancerFactory nativeQuery, QueryEnhancerFactory jpql) {
+ this.nativeQuery = nativeQuery;
+ this.jpql = jpql;
+ }
+
+ /**
+ * Returns the default JPQL {@link QueryEnhancerFactory} based on class path presence of Hibernate and EclipseLink.
+ *
+ * @return the default JPQL {@link QueryEnhancerFactory}.
+ */
+ public static QueryEnhancerFactory jpql() {
+ return DEFAULT_JPQL;
+ }
+
+ @Override
+ public QueryEnhancerFactory select(DeclaredQuery query) {
+ return jpql.supports(query) ? jpql : nativeQuery;
+ }
+
+ }
+}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactory.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactory.java
index 27e55e2f7e..cc767fd685 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactory.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactory.java
@@ -54,7 +54,7 @@ abstract class QueryParameterSetterFactory {
* @return
*/
@Nullable
- abstract QueryParameterSetter create(ParameterBinding binding);
+ abstract QueryParameterSetter create(ParameterBinding binding, IntrospectedQuery introspectedQuery);
/**
* Creates a new {@link QueryParameterSetterFactory} for the given {@link JpaParameters}.
@@ -116,8 +116,8 @@ private static QueryParameterSetter createSetter(Function String.format( //
- "At least %s parameter(s) provided but only %s parameter(s) present in query", //
- binding.getRequiredPosition(), //
- parameters.getNumberOfParameters() //
- ) //
- );
+ public QueryParameterSetter create(ParameterBinding binding, IntrospectedQuery query) {
if (binding instanceof ParameterBinding.PartTreeParameterBinding ptb) {
@@ -318,7 +303,7 @@ public QueryParameterSetter create(ParameterBinding binding) {
return QueryParameterSetter.NOOP;
}
- return super.create(binding);
+ return super.create(binding, query);
}
return null;
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java
index dfe6e739a9..76ba921967 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java
@@ -446,7 +446,7 @@ private static String toJpaDirection(Order order) {
*
* @param query must not be {@literal null}.
* @return Might return {@literal null}.
- * @deprecated use {@link DeclaredQuery#getAlias()} instead.
+ * @deprecated use {@link IntrospectedQuery#getAlias()} instead.
*/
@Nullable
@Deprecated
@@ -579,7 +579,7 @@ public static Query applyAndBind(String queryString, Iterable entities, E
*
* @param originalQuery must not be {@literal null} or empty.
* @return Guaranteed to be not {@literal null}.
- * @deprecated use {@link DeclaredQuery#deriveCountQuery(String)} instead.
+ * @deprecated use {@link IntrospectedQuery#deriveCountQuery(String)} instead.
*/
@Deprecated
public static String createCountQueryFor(String originalQuery) {
@@ -593,7 +593,7 @@ public static String createCountQueryFor(String originalQuery) {
* @param countProjection may be {@literal null}.
* @return a query String to be used a count query for pagination. Guaranteed to be not {@literal null}.
* @since 1.6
- * @deprecated use {@link DeclaredQuery#deriveCountQuery(String)} instead.
+ * @deprecated use {@link IntrospectedQuery#deriveCountQuery(String)} instead.
*/
@Deprecated
public static String createCountQueryFor(String originalQuery, @Nullable String countProjection) {
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 b90648223b..32c57331a2 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,9 +18,7 @@
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
-import org.springframework.data.jpa.repository.QueryRewriter;
import org.springframework.data.repository.query.RepositoryQuery;
-import org.springframework.data.repository.query.ValueExpressionDelegate;
import org.springframework.lang.Nullable;
/**
@@ -33,36 +31,21 @@
* @author Mark Paluch
* @author Greg Turnquist
*/
-final class SimpleJpaQuery extends AbstractStringBasedJpaQuery {
-
- /**
- * Creates a new {@link SimpleJpaQuery} encapsulating the query annotated on the given {@link JpaQueryMethod}.
- *
- * @param method must not be {@literal null}
- * @param em must not be {@literal null}
- * @param countQueryString
- * @param queryRewriter must not be {@literal null}
- * @param valueExpressionDelegate must not be {@literal null}
- */
- public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, @Nullable String countQueryString,
- QueryRewriter queryRewriter, ValueExpressionDelegate valueExpressionDelegate) {
- this(method, em, method.getRequiredAnnotatedQuery(), countQueryString, queryRewriter, valueExpressionDelegate);
- }
+class SimpleJpaQuery extends AbstractStringBasedJpaQuery {
/**
* Creates a new {@link SimpleJpaQuery} that encapsulates a simple query string.
*
- * @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 queryRewriter
- * @param valueExpressionDelegate must not be {@literal null}
+ * @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 can be {@literal null} if not defined.
+ * @param queryConfiguration must not be {@literal null}.
*/
- public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, String queryString, @Nullable String countQueryString, QueryRewriter queryRewriter,
- ValueExpressionDelegate valueExpressionDelegate) {
+ public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, String queryString, @Nullable String countQueryString,
+ JpaQueryConfiguration queryConfiguration) {
- super(method, em, queryString, countQueryString, queryRewriter, valueExpressionDelegate);
+ super(method, em, queryString, countQueryString, queryConfiguration);
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/query/StringQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java
index 10424d702c..90e86587d6 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java
@@ -26,6 +26,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.springframework.data.domain.Sort;
import org.springframework.data.expression.ValueExpression;
import org.springframework.data.expression.ValueExpressionParser;
import org.springframework.data.jpa.repository.query.ParameterBinding.BindingIdentifier;
@@ -57,13 +58,14 @@
* @author Greg Turnquist
* @author Yuriy Tsarkov
*/
-class StringQuery implements DeclaredQuery {
+class StringQuery implements EntityQuery {
private final String query;
private final List bindings;
private final boolean containsPageableInSpel;
private final boolean usesJdbcStyleParameters;
private final boolean isNative;
+ private final QueryEnhancerFactory queryEnhancerFactory;
private final QueryEnhancer queryEnhancer;
private final boolean hasNamedParameters;
@@ -73,19 +75,29 @@ class StringQuery implements DeclaredQuery {
* @param query must not be {@literal null} or empty.
*/
public StringQuery(String query, boolean isNative) {
+ this(query, isNative, QueryEnhancerSelector.DEFAULT_SELECTOR);
+ }
+
+ /**
+ * Creates a new {@link StringQuery} from the given JPQL query.
+ *
+ * @param query must not be {@literal null} or empty.
+ */
+ StringQuery(String query, boolean isNative, QueryEnhancerFactory factory) {
Assert.hasText(query, "Query must not be null or empty");
this.isNative = isNative;
this.bindings = new ArrayList<>();
this.containsPageableInSpel = query.contains("#pageable");
+ this.queryEnhancerFactory = factory;
Metadata queryMeta = new Metadata();
this.query = ParameterBindingParser.INSTANCE.parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(query,
this.bindings, queryMeta);
this.usesJdbcStyleParameters = queryMeta.usesJdbcStyleParameters;
- this.queryEnhancer = QueryEnhancerFactory.forQuery(this);
+ this.queryEnhancer = factory.create(this);
boolean hasNamedParameters = false;
for (ParameterBinding parameterBinding : getParameterBindings()) {
@@ -98,6 +110,42 @@ public StringQuery(String query, boolean isNative) {
this.hasNamedParameters = hasNamedParameters;
}
+ /**
+ * Creates a new {@link StringQuery} from the given JPQL query.
+ *
+ * @param query must not be {@literal null} or empty.
+ */
+ StringQuery(String query, boolean isNative, QueryEnhancerSelector selector) {
+
+ Assert.hasText(query, "Query must not be null or empty");
+
+ this.isNative = isNative;
+ this.bindings = new ArrayList<>();
+ this.containsPageableInSpel = query.contains("#pageable");
+
+ Metadata queryMeta = new Metadata();
+ this.query = ParameterBindingParser.INSTANCE.parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(query,
+ this.bindings, queryMeta);
+
+ this.usesJdbcStyleParameters = queryMeta.usesJdbcStyleParameters;
+ this.queryEnhancerFactory = selector.select(this);
+ this.queryEnhancer = queryEnhancerFactory.create(this);
+
+ boolean hasNamedParameters = false;
+ for (ParameterBinding parameterBinding : getParameterBindings()) {
+ if (parameterBinding.getIdentifier().hasName() && parameterBinding.getOrigin().isMethodArgument()) {
+ hasNamedParameters = true;
+ break;
+ }
+ }
+
+ this.hasNamedParameters = hasNamedParameters;
+ }
+
+ QueryEnhancer getQueryEnhancer() {
+ return queryEnhancer;
+ }
+
/**
* Returns whether we have found some like bindings.
*/
@@ -115,10 +163,10 @@ public List getParameterBindings() {
}
@Override
- public DeclaredQuery deriveCountQuery(@Nullable String countQueryProjection) {
+ public IntrospectedQuery deriveCountQuery(@Nullable String countQueryProjection) {
StringQuery stringQuery = new StringQuery(this.queryEnhancer.createCountQueryFor(countQueryProjection), //
- this.isNative);
+ this.isNative, this.queryEnhancerFactory);
if (this.hasParameterBindings() && !this.getParameterBindings().equals(stringQuery.getParameterBindings())) {
stringQuery.getParameterBindings().clear();
@@ -128,6 +176,11 @@ public DeclaredQuery deriveCountQuery(@Nullable String countQueryProjection) {
return stringQuery;
}
+ @Override
+ public String applySorting(Sort sort) {
+ return queryEnhancer.applySorting(sort);
+ }
+
@Override
public boolean usesJdbcStyleParameters() {
return usesJdbcStyleParameters;
@@ -138,7 +191,6 @@ public String getQueryString() {
return query;
}
- @Override
@Nullable
public String getAlias() {
return queryEnhancer.detectAlias();
@@ -243,8 +295,7 @@ String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(String que
}
ValueExpressionQueryRewriter.ParsedQuery parsedQuery = createSpelExtractor(query,
- parametersShouldBeAccessedByIndex,
- greatestParameterIndex);
+ parametersShouldBeAccessedByIndex, greatestParameterIndex);
String resultingQuery = parsedQuery.getQueryString();
Matcher matcher = PARAMETER_BINDING_PATTERN.matcher(resultingQuery);
@@ -305,16 +356,18 @@ String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(String que
BindingIdentifier targetBinding = queryParameter;
Function bindingFactory = switch (ParameterBindingType.of(typeSource)) {
- case LIKE -> {
+ case LIKE -> {
- Type likeType = LikeParameterBinding.getLikeTypeFrom(matcher.group(2));
- yield (identifier) -> new LikeParameterBinding(identifier, origin, likeType);
- }
- case IN -> (identifier) -> new InParameterBinding(identifier, origin); // fall-through we don't need a special parameter queryParameter for the given parameter.
- default -> (identifier) -> new ParameterBinding(identifier, origin);
- };
+ Type likeType = LikeParameterBinding.getLikeTypeFrom(matcher.group(2));
+ yield (identifier) -> new LikeParameterBinding(identifier, origin, likeType);
+ }
+ case IN -> (identifier) -> new InParameterBinding(identifier, origin); // fall-through we don't need a special
+ // parameter queryParameter for the
+ // given parameter.
+ default -> (identifier) -> new ParameterBinding(identifier, origin);
+ };
- if (origin.isExpression()) {
+ if (origin.isExpression()) {
parameterBindings.register(bindingFactory.apply(queryParameter));
} else {
targetBinding = parameterBindings.register(queryParameter, origin, bindingFactory);
@@ -342,8 +395,7 @@ String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(String que
}
private static ValueExpressionQueryRewriter.ParsedQuery createSpelExtractor(String queryWithSpel,
- boolean parametersShouldBeAccessedByIndex,
- int greatestParameterIndex) {
+ boolean parametersShouldBeAccessedByIndex, int greatestParameterIndex) {
/*
* If parameters need to be bound by index, we bind the synthetic expression parameters starting from position of the greatest discovered index parameter in order to
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 e14658773b..22a33dcea0 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
@@ -34,17 +34,8 @@
import org.springframework.dao.InvalidDataAccessApiUsageException;
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.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.repository.query.*;
import org.springframework.data.jpa.util.JpaMetamodel;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.querydsl.EntityPathResolver;
@@ -82,12 +73,12 @@
public class JpaRepositoryFactory extends RepositoryFactorySupport {
private final EntityManager entityManager;
- private final QueryExtractor extractor;
private final CrudMethodMetadataPostProcessor crudMethodMetadataPostProcessor;
private final CrudMethodMetadata crudMethodMetadata;
private EntityPathResolver entityPathResolver;
private EscapeCharacter escapeCharacter = EscapeCharacter.DEFAULT;
+ private QueryEnhancerSelector queryEnhancerSelector = QueryEnhancerSelector.DEFAULT_SELECTOR;
private JpaQueryMethodFactory queryMethodFactory;
private QueryRewriterProvider queryRewriterProvider;
@@ -101,7 +92,7 @@ public JpaRepositoryFactory(EntityManager entityManager) {
Assert.notNull(entityManager, "EntityManager must not be null");
this.entityManager = entityManager;
- this.extractor = PersistenceProvider.fromEntityManager(entityManager);
+ PersistenceProvider extractor = PersistenceProvider.fromEntityManager(entityManager);
this.crudMethodMetadataPostProcessor = new CrudMethodMetadataPostProcessor();
this.entityPathResolver = SimpleEntityPathResolver.INSTANCE;
this.queryMethodFactory = new DefaultJpaQueryMethodFactory(extractor);
@@ -179,6 +170,19 @@ public void setQueryMethodFactory(JpaQueryMethodFactory queryMethodFactory) {
this.queryMethodFactory = queryMethodFactory;
}
+ /**
+ * Configures the {@link QueryEnhancerSelector} to be used. Defaults to
+ * {@link QueryEnhancerSelector#DEFAULT_SELECTOR}.
+ *
+ * @param queryEnhancerSelector must not be {@literal null}.
+ */
+ public void setQueryEnhancerSelector(QueryEnhancerSelector queryEnhancerSelector) {
+
+ Assert.notNull(queryEnhancerSelector, "QueryEnhancerSelector must not be null");
+
+ this.queryEnhancerSelector = queryEnhancerSelector;
+ }
+
/**
* Configures the {@link QueryRewriterProvider} to be used. Defaults to instantiate query rewriters through
* {@link BeanUtils#instantiateClass(Class)}.
@@ -238,12 +242,14 @@ protected ProjectionFactory getProjectionFactory(ClassLoader classLoader, BeanFa
@Override
protected Optional getQueryLookupStrategy(@Nullable Key key,
ValueExpressionDelegate valueExpressionDelegate) {
+
+ JpaQueryConfiguration queryConfiguration = new JpaQueryConfiguration(queryRewriterProvider, queryEnhancerSelector,
+ new CachingValueExpressionDelegate(valueExpressionDelegate), escapeCharacter);
+
return Optional.of(JpaQueryLookupStrategy.create(entityManager, queryMethodFactory, key,
- new CachingValueExpressionDelegate(valueExpressionDelegate),
- queryRewriterProvider, escapeCharacter));
+ queryConfiguration));
}
-
@Override
@SuppressWarnings("unchecked")
public JpaEntityInformation getEntityInformation(Class domainClass) {
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBean.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBean.java
index 86f2f14d6c..665c3949c8 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBean.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBean.java
@@ -18,10 +18,16 @@
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
+import java.util.function.Function;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.data.jpa.repository.query.EscapeCharacter;
import org.springframework.data.jpa.repository.query.JpaQueryMethodFactory;
+import org.springframework.data.jpa.repository.query.QueryEnhancerSelector;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.querydsl.SimpleEntityPathResolver;
@@ -45,10 +51,12 @@
public class JpaRepositoryFactoryBean, S, ID>
extends TransactionalRepositoryFactoryBeanSupport {
+ private @Nullable BeanFactory beanFactory;
private @Nullable EntityManager entityManager;
private EntityPathResolver entityPathResolver;
private EscapeCharacter escapeCharacter = EscapeCharacter.DEFAULT;
private JpaQueryMethodFactory queryMethodFactory;
+ private @Nullable Function queryEnhancerSelectorSource;
/**
* Creates a new {@link JpaRepositoryFactoryBean} for the given repository interface.
@@ -74,6 +82,12 @@ public void setMappingContext(MappingContext, ?> mappingContext) {
super.setMappingContext(mappingContext);
}
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) {
+ this.beanFactory = beanFactory;
+ super.setBeanFactory(beanFactory);
+ }
+
/**
* Configures the {@link EntityPathResolver} to be used. Will expect a canonical bean to be present but fallback to
* {@link SimpleEntityPathResolver#INSTANCE} in case none is available.
@@ -100,6 +114,43 @@ public void setQueryMethodFactory(@Nullable JpaQueryMethodFactory factory) {
}
}
+ /**
+ * Configures the {@link QueryEnhancerSelector} to be used. Defaults to
+ * {@link QueryEnhancerSelector#DEFAULT_SELECTOR}.
+ *
+ * @param queryEnhancerSelectorSource must not be {@literal null}.
+ */
+ public void setQueryEnhancerSelectorSource(QueryEnhancerSelector queryEnhancerSelectorSource) {
+ this.queryEnhancerSelectorSource = bf -> queryEnhancerSelectorSource;
+ }
+
+ /**
+ * Configures the {@link QueryEnhancerSelector} to be used.
+ *
+ * @param queryEnhancerSelectorType must not be {@literal null}.
+ */
+ public void setQueryEnhancerSelector(Class extends QueryEnhancerSelector> queryEnhancerSelectorType) {
+
+ this.queryEnhancerSelectorSource = bf -> {
+
+ if (bf != null) {
+
+ ObjectProvider extends QueryEnhancerSelector> beanProvider = bf.getBeanProvider(queryEnhancerSelectorType);
+ QueryEnhancerSelector selector = beanProvider.getIfAvailable();
+
+ if (selector != null) {
+ return selector;
+ }
+
+ if (bf instanceof AutowireCapableBeanFactory acbf) {
+ return acbf.createBean(queryEnhancerSelectorType);
+ }
+ }
+
+ return BeanUtils.instantiateClass(queryEnhancerSelectorType);
+ };
+ }
+
@Override
protected RepositoryFactorySupport doCreateRepositoryFactory() {
@@ -113,15 +164,19 @@ protected RepositoryFactorySupport doCreateRepositoryFactory() {
*/
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
- JpaRepositoryFactory jpaRepositoryFactory = new JpaRepositoryFactory(entityManager);
- jpaRepositoryFactory.setEntityPathResolver(entityPathResolver);
- jpaRepositoryFactory.setEscapeCharacter(escapeCharacter);
+ JpaRepositoryFactory factory = new JpaRepositoryFactory(entityManager);
+ factory.setEntityPathResolver(entityPathResolver);
+ factory.setEscapeCharacter(escapeCharacter);
if (queryMethodFactory != null) {
- jpaRepositoryFactory.setQueryMethodFactory(queryMethodFactory);
+ factory.setQueryMethodFactory(queryMethodFactory);
+ }
+
+ if (queryEnhancerSelectorSource != null) {
+ factory.setQueryEnhancerSelector(queryEnhancerSelectorSource.apply(beanFactory));
}
- return jpaRepositoryFactory;
+ return factory;
}
@Override
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 6590db4022..204471b6d9 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,7 +34,6 @@
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;
@@ -53,6 +52,9 @@
@ContextConfiguration("classpath:infrastructure.xml")
class AbstractStringBasedJpaQueryIntegrationTests {
+ private static final JpaQueryConfiguration CONFIG = new JpaQueryConfiguration(QueryRewriterProvider.simple(),
+ QueryEnhancerSelector.DEFAULT_SELECTOR, ValueExpressionDelegate.create(), EscapeCharacter.DEFAULT);
+
@PersistenceContext EntityManager em;
@Autowired BeanFactory beanFactory;
@@ -66,8 +68,7 @@ void createsNormalQueryForJpaManagedReturnTypes() throws Exception {
when(mock.getMetamodel()).thenReturn(em.getMetamodel());
JpaQueryMethod method = getMethod("findRolesByEmailAddress", String.class);
- AbstractStringBasedJpaQuery jpaQuery = new SimpleJpaQuery(method, mock, null, QueryRewriter.IdentityQueryRewriter.INSTANCE,
- ValueExpressionDelegate.create());
+ AbstractStringBasedJpaQuery jpaQuery = new SimpleJpaQuery(method, mock, method.getAnnotatedQuery(), null, CONFIG);
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/AbstractStringBasedJpaQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryUnitTests.java
index 3fb97409f8..b7b245c424 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryUnitTests.java
@@ -35,7 +35,6 @@
import org.springframework.data.domain.Sort;
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.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.RepositoryMetadata;
@@ -56,6 +55,9 @@
*/
class AbstractStringBasedJpaQueryUnitTests {
+ private static final JpaQueryConfiguration CONFIG = new JpaQueryConfiguration(QueryRewriterProvider.simple(),
+ QueryEnhancerSelector.DEFAULT_SELECTOR, ValueExpressionDelegate.create(), EscapeCharacter.DEFAULT);
+
@Test // GH-3310
void shouldNotAttemptToAppendSortIfNoSortArgumentPresent() {
@@ -118,8 +120,8 @@ static InvocationCapturingStringQueryStub forMethod(Class> repository, String
Query query = AnnotatedElementUtils.getMergedAnnotation(respositoryMethod, Query.class);
- return new InvocationCapturingStringQueryStub(respositoryMethod, queryMethod, query.value(), query.countQuery());
-
+ return new InvocationCapturingStringQueryStub(respositoryMethod, queryMethod, query.value(), query.countQuery(),
+ CONFIG);
}
static class InvocationCapturingStringQueryStub extends AbstractStringBasedJpaQuery {
@@ -128,7 +130,7 @@ static class InvocationCapturingStringQueryStub extends AbstractStringBasedJpaQu
private final MultiValueMap capturedArguments = new LinkedMultiValueMap<>(3);
InvocationCapturingStringQueryStub(Method targetMethod, JpaQueryMethod queryMethod, String queryString,
- @Nullable String countQueryString) {
+ @Nullable String countQueryString, JpaQueryConfiguration queryConfiguration) {
super(queryMethod, new Supplier() {
@Override
@@ -142,8 +144,7 @@ public EntityManager get() {
return em;
}
- }.get(), queryString, countQueryString, Mockito.mock(QueryRewriter.class),
- ValueExpressionDelegate.create());
+ }.get(), queryString, countQueryString, queryConfiguration);
this.targetMethod = targetMethod;
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/DefaultQueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/DefaultQueryEnhancerUnitTests.java
index 43a87c8282..43c0910fbb 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/DefaultQueryEnhancerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/DefaultQueryEnhancerUnitTests.java
@@ -30,8 +30,8 @@
public class DefaultQueryEnhancerUnitTests extends QueryEnhancerTckTests {
@Override
- QueryEnhancer createQueryEnhancer(DeclaredQuery declaredQuery) {
- return new DefaultQueryEnhancer(declaredQuery);
+ QueryEnhancer createQueryEnhancer(DeclaredQuery query) {
+ return new DefaultQueryEnhancer(query);
}
@Override
@@ -42,7 +42,7 @@ void shouldDeriveNativeCountQueryWithVariable(String query, String expected) {}
@Test // GH-3546
void shouldApplySorting() {
- QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.of("SELECT e FROM Employee e", true));
+ QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.ofNative("SELECT e FROM Employee e"));
String sql = enhancer.applySorting(Sort.by("foo", "bar"));
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlParserQueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlParserQueryEnhancerUnitTests.java
index 8895fc4c19..5303378b84 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlParserQueryEnhancerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlParserQueryEnhancerUnitTests.java
@@ -32,7 +32,7 @@ QueryEnhancer createQueryEnhancer(DeclaredQuery query) {
assumeThat(query.isNativeQuery()).isFalse();
- return JpaQueryEnhancer.forEql(query);
+ return JpaQueryEnhancer.forEql(query.getQueryString());
}
@Override
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryTransformerTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryTransformerTests.java
index 3c1fec2ed3..efd30132ec 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryTransformerTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryTransformerTests.java
@@ -827,6 +827,6 @@ private String projection(String query) {
}
private QueryEnhancer newParser(String query) {
- return JpaQueryEnhancer.forEql(DeclaredQuery.of(query, false));
+ return JpaQueryEnhancer.forEql(query);
}
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java
index 1df1abde12..96e7b9167f 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java
@@ -28,8 +28,8 @@
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
-import org.springframework.data.expression.ValueExpressionParser;
import org.springframework.data.jpa.repository.query.ParameterBinding.LikeParameterBinding;
+import org.springframework.data.repository.query.ValueExpressionDelegate;
import org.springframework.data.repository.query.parser.Part.Type;
/**
@@ -47,7 +47,9 @@
@MockitoSettings(strictness = Strictness.LENIENT)
class ExpressionBasedStringQueryUnitTests {
- private static final ValueExpressionParser PARSER = ValueExpressionParser.create();
+ private static final JpaQueryConfiguration CONFIG = new JpaQueryConfiguration(QueryRewriterProvider.simple(),
+ QueryEnhancerSelector.DEFAULT_SELECTOR, ValueExpressionDelegate.create(), EscapeCharacter.DEFAULT);
+
@Mock JpaEntityMetadata> metadata;
@BeforeEach
@@ -59,14 +61,16 @@ void setUp() {
void shouldReturnQueryWithDomainTypeExpressionReplacedWithSimpleDomainTypeName() {
String source = "select u from #{#entityName} u where u.firstname like :firstname";
- StringQuery query = new ExpressionBasedStringQuery(source, metadata, PARSER, false);
+ StringQuery query = new ExpressionBasedStringQuery(source, metadata,
+ CONFIG.getValueExpressionDelegate().getValueExpressionParser(), false, CONFIG.getSelector());
assertThat(query.getQueryString()).isEqualTo("select u from User u where u.firstname like :firstname");
}
@Test // DATAJPA-424
void renderAliasInExpressionQueryCorrectly() {
- StringQuery query = new ExpressionBasedStringQuery("select u from #{#entityName} u", metadata, PARSER, true);
+ StringQuery query = new ExpressionBasedStringQuery("select u from #{#entityName} u", metadata,
+ CONFIG.getValueExpressionDelegate().getValueExpressionParser(), true, CONFIG.getSelector());
assertThat(query.getAlias()).isEqualTo("u");
assertThat(query.getQueryString()).isEqualTo("select u from User u");
}
@@ -79,7 +83,7 @@ void shouldDetectBindParameterCountCorrectly() {
+ "AND (LOWER(n.server) LIKE LOWER(:#{#networkRequest.server})) OR :#{#networkRequest.server} IS NULL "
+ "AND (n.createdAt >= :#{#networkRequest.createdTime.startDateTime}) AND (n.createdAt <=:#{#networkRequest.createdTime.endDateTime}) "
+ "AND (n.updatedAt >= :#{#networkRequest.updatedTime.startDateTime}) AND (n.updatedAt <=:#{#networkRequest.updatedTime.endDateTime})",
- metadata, PARSER, false);
+ metadata, CONFIG.getValueExpressionDelegate().getValueExpressionParser(), false, CONFIG.getSelector());
assertThat(query.getParameterBindings()).hasSize(8);
}
@@ -92,7 +96,7 @@ void shouldDetectBindParameterCountCorrectlyWithJDBCStyleParameters() {
+ "AND (LOWER(n.server) LIKE LOWER(NULLIF(text(concat('%',?#{#networkRequest.server},'%')), '')) OR ?#{#networkRequest.server} IS NULL)"
+ "AND (n.createdAt >= ?#{#networkRequest.createdTime.startDateTime}) AND (n.createdAt <=?#{#networkRequest.createdTime.endDateTime})"
+ "AND (n.updatedAt >= ?#{#networkRequest.updatedTime.startDateTime}) AND (n.updatedAt <=?#{#networkRequest.updatedTime.endDateTime})",
- metadata, PARSER, false);
+ metadata, CONFIG.getValueExpressionDelegate().getValueExpressionParser(), false, CONFIG.getSelector());
assertThat(query.getParameterBindings()).hasSize(8);
}
@@ -105,7 +109,7 @@ void shouldDetectComplexNativeQueriesWithSpelAsNonNative() {
+ "AND (LOWER(n.server) LIKE LOWER(NULLIF(text(concat('%',?#{#networkRequest.server},'%')), '')) OR ?#{#networkRequest.server} IS NULL)"
+ "AND (n.createdAt >= ?#{#networkRequest.createdTime.startDateTime}) AND (n.createdAt <=?#{#networkRequest.createdTime.endDateTime})"
+ "AND (n.updatedAt >= ?#{#networkRequest.updatedTime.startDateTime}) AND (n.updatedAt <=?#{#networkRequest.updatedTime.endDateTime})",
- metadata, PARSER, true);
+ metadata, CONFIG.getValueExpressionDelegate().getValueExpressionParser(), false, CONFIG.getSelector());
assertThat(query.isNativeQuery()).isFalse();
}
@@ -113,7 +117,8 @@ void shouldDetectComplexNativeQueriesWithSpelAsNonNative() {
@Test
void shouldDetectSimpleNativeQueriesWithSpelAsNonNative() {
- StringQuery query = new ExpressionBasedStringQuery("select n from #{#entityName} n", metadata, PARSER, true);
+ StringQuery query = new ExpressionBasedStringQuery("select n from #{#entityName} n", metadata,
+ CONFIG.getValueExpressionDelegate().getValueExpressionParser(), true, CONFIG.getSelector());
assertThat(query.isNativeQuery()).isFalse();
}
@@ -121,7 +126,8 @@ void shouldDetectSimpleNativeQueriesWithSpelAsNonNative() {
@Test
void shouldDetectSimpleNativeQueriesWithoutSpelAsNative() {
- StringQuery query = new ExpressionBasedStringQuery("select u from User u", metadata, PARSER, true);
+ StringQuery query = new ExpressionBasedStringQuery("select u from User u", metadata,
+ CONFIG.getValueExpressionDelegate().getValueExpressionParser(), true, CONFIG.getSelector());
assertThat(query.isNativeQuery()).isTrue();
}
@@ -130,8 +136,8 @@ void shouldDetectSimpleNativeQueriesWithoutSpelAsNative() {
void namedExpressionsShouldCreateLikeBindings() {
StringQuery query = new ExpressionBasedStringQuery(
- "select u from User u where u.firstname like %:#{foo} or u.firstname like :#{foo}%", metadata, PARSER,
- false);
+ "select u from User u where u.firstname like %:#{foo} or u.firstname like :#{foo}%", metadata,
+ CONFIG.getValueExpressionDelegate().getValueExpressionParser(), false, CONFIG.getSelector());
assertThat(query.hasParameterBindings()).isTrue();
assertThat(query.getQueryString()).isEqualTo(
@@ -155,8 +161,8 @@ void namedExpressionsShouldCreateLikeBindings() {
void indexedExpressionsShouldCreateLikeBindings() {
StringQuery query = new ExpressionBasedStringQuery(
- "select u from User u where u.firstname like %?#{foo} or u.firstname like ?#{foo}%", metadata, PARSER,
- false);
+ "select u from User u where u.firstname like %?#{foo} or u.firstname like ?#{foo}%", metadata,
+ CONFIG.getValueExpressionDelegate().getValueExpressionParser(), false, CONFIG.getSelector());
assertThat(query.hasParameterBindings()).isTrue();
assertThat(query.getQueryString())
@@ -180,7 +186,7 @@ void indexedExpressionsShouldCreateLikeBindings() {
public void doesTemplatingWhenEntityNameSpelIsPresent() {
StringQuery query = new ExpressionBasedStringQuery("select #{#entityName + 'Hallo'} from #{#entityName} u",
- metadata, PARSER, false);
+ metadata, CONFIG.getValueExpressionDelegate().getValueExpressionParser(), false, CONFIG.getSelector());
assertThat(query.getQueryString()).isEqualTo("select UserHallo from User u");
}
@@ -189,7 +195,7 @@ public void doesTemplatingWhenEntityNameSpelIsPresent() {
public void doesNoTemplatingWhenEntityNameSpelIsNotPresent() {
StringQuery query = new ExpressionBasedStringQuery("select #{#entityName + 'Hallo'} from User u", metadata,
- PARSER, false);
+ CONFIG.getValueExpressionDelegate().getValueExpressionParser(), false, CONFIG.getSelector());
assertThat(query.getQueryString()).isEqualTo("select UserHallo from User u");
}
@@ -198,7 +204,7 @@ public void doesNoTemplatingWhenEntityNameSpelIsNotPresent() {
public void doesTemplatingWhenEntityNameSpelIsPresentForBindParameter() {
StringQuery query = new ExpressionBasedStringQuery("select u from #{#entityName} u where name = :#{#something}",
- metadata, PARSER, false);
+ metadata, CONFIG.getValueExpressionDelegate().getValueExpressionParser(), false, CONFIG.getSelector());
assertThat(query.getQueryString()).isEqualTo("select u from User u where name = :__$synthetic$__1");
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserQueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserQueryEnhancerUnitTests.java
index ef7b269115..916db5e06a 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserQueryEnhancerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserQueryEnhancerUnitTests.java
@@ -32,7 +32,7 @@ QueryEnhancer createQueryEnhancer(DeclaredQuery query) {
assumeThat(query.isNativeQuery()).isFalse();
- return JpaQueryEnhancer.forHql(query);
+ return JpaQueryEnhancer.forHql(query.getQueryString());
}
@Override
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java
index 867e3f87b2..2b7e884e0c 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java
@@ -1197,6 +1197,6 @@ private String projection(String query) {
}
private QueryEnhancer newParser(String query) {
- return JpaQueryEnhancer.forHql(DeclaredQuery.of(query, false));
+ return JpaQueryEnhancer.forHql(query);
}
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerUnitTests.java
index dee9d10d66..a3977b8a64 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerUnitTests.java
@@ -37,14 +37,14 @@
public class JSqlParserQueryEnhancerUnitTests extends QueryEnhancerTckTests {
@Override
- QueryEnhancer createQueryEnhancer(DeclaredQuery declaredQuery) {
- return new JSqlParserQueryEnhancer(declaredQuery);
+ QueryEnhancer createQueryEnhancer(DeclaredQuery query) {
+ return new JSqlParserQueryEnhancer(query);
}
@Test // GH-3546
void shouldApplySorting() {
- QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.of("SELECT e FROM Employee e", true));
+ QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.ofJpql("SELECT e FROM Employee e"));
String sql = enhancer.applySorting(Sort.by("foo", "bar"));
@@ -54,13 +54,13 @@ void shouldApplySorting() {
@Test // GH-3707
void countQueriesShouldConsiderPrimaryTableAlias() {
- QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.of("""
+ QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.ofNative("""
SELECT DISTINCT a.*, b.b1
FROM TableA a
JOIN TableB b ON a.b = b.b
LEFT JOIN TableC c ON b.c = c.c
ORDER BY b.b1, a.a1, a.a2
- """, true));
+ """));
String sql = enhancer.createCountQueryFor();
@@ -83,7 +83,7 @@ void setOperationListWorks() {
+ "select SOME_COLUMN from SOME_OTHER_TABLE where REPORTING_DATE = :REPORTING_DATE";
StringQuery stringQuery = new StringQuery(setQuery, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery).create(stringQuery);
assertThat(stringQuery.getAlias()).isNullOrEmpty();
assertThat(stringQuery.getProjection()).isEqualToIgnoringCase("SOME_COLUMN");
@@ -106,7 +106,7 @@ void complexSetOperationListWorks() {
+ "union select SOME_COLUMN from SOME_OTHER_OTHER_TABLE";
StringQuery stringQuery = new StringQuery(setQuery, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery).create(stringQuery);
assertThat(stringQuery.getAlias()).isNullOrEmpty();
assertThat(stringQuery.getProjection()).isEqualToIgnoringCase("SOME_COLUMN");
@@ -133,7 +133,7 @@ void deeplyNestedcomplexSetOperationListWorks() {
+ "\t;";
StringQuery stringQuery = new StringQuery(setQuery, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery).create(stringQuery);
assertThat(stringQuery.getAlias()).isNullOrEmpty();
assertThat(stringQuery.getProjection()).isEqualToIgnoringCase("CustomerID");
@@ -153,7 +153,7 @@ void valuesStatementsWorks() {
String setQuery = "VALUES (1, 2, 'test')";
StringQuery stringQuery = new StringQuery(setQuery, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery).create(stringQuery);
assertThat(stringQuery.getAlias()).isNullOrEmpty();
assertThat(stringQuery.getProjection()).isNullOrEmpty();
@@ -174,7 +174,7 @@ void withStatementsWorks() {
+ "select day, value from sample_data as a";
StringQuery stringQuery = new StringQuery(setQuery, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery).create(stringQuery);
assertThat(stringQuery.getAlias()).isEqualToIgnoringCase("a");
assertThat(stringQuery.getProjection()).isEqualToIgnoringCase("day, value");
@@ -197,7 +197,7 @@ void multipleWithStatementsWorks() {
+ "select day, value from sample_data as a";
StringQuery stringQuery = new StringQuery(setQuery, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery).create(stringQuery);
assertThat(stringQuery.getAlias()).isEqualToIgnoringCase("a");
assertThat(stringQuery.getProjection()).isEqualToIgnoringCase("day, value");
@@ -217,7 +217,7 @@ void multipleWithStatementsWorks() {
void truncateStatementShouldWork() {
StringQuery stringQuery = new StringQuery("TRUNCATE TABLE foo", true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery).create(stringQuery);
assertThat(stringQuery.getAlias()).isNull();
assertThat(stringQuery.getProjection()).isEmpty();
@@ -235,7 +235,7 @@ void truncateStatementShouldWork() {
void mergeStatementWorksWithJSqlParser(String query, String alias) {
StringQuery stringQuery = new StringQuery(query, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery).create(stringQuery);
assertThat(queryEnhancer.detectAlias()).isEqualTo(alias);
assertThat(QueryUtils.detectAlias(query)).isNull();
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 861272154b..e68faf4092 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
@@ -34,7 +34,6 @@
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.Pageable;
import org.springframework.data.domain.Sort;
@@ -64,7 +63,8 @@
@MockitoSettings(strictness = Strictness.LENIENT)
class JpaQueryLookupStrategyUnitTests {
- private static final ValueExpressionDelegate VALUE_EXPRESSION_DELEGATE = ValueExpressionDelegate.create();
+ private static final JpaQueryConfiguration CONFIG = new JpaQueryConfiguration(QueryRewriterProvider.simple(),
+ QueryEnhancerSelector.DEFAULT_SELECTOR, ValueExpressionDelegate.create(), EscapeCharacter.DEFAULT);
@Mock EntityManager em;
@Mock EntityManagerFactory emf;
@@ -72,7 +72,6 @@ class JpaQueryLookupStrategyUnitTests {
@Mock NamedQueries namedQueries;
@Mock Metamodel metamodel;
@Mock ProjectionFactory projectionFactory;
- @Mock BeanFactory beanFactory;
private JpaQueryMethodFactory queryMethodFactory;
@@ -90,7 +89,7 @@ void setUp() {
void invalidAnnotatedQueryCausesException() throws Exception {
QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND,
- VALUE_EXPRESSION_DELEGATE, new BeanFactoryQueryRewriterProvider(beanFactory), EscapeCharacter.DEFAULT);
+ CONFIG);
Method method = UserRepository.class.getMethod("findByFoo", String.class);
RepositoryMetadata metadata = new DefaultRepositoryMetadata(UserRepository.class);
@@ -102,7 +101,7 @@ void invalidAnnotatedQueryCausesException() throws Exception {
void considersNamedCountQuery() throws Exception {
QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND,
- VALUE_EXPRESSION_DELEGATE, new BeanFactoryQueryRewriterProvider(beanFactory), EscapeCharacter.DEFAULT);
+ CONFIG);
when(namedQueries.hasQuery("foo.count")).thenReturn(true);
when(namedQueries.getQuery("foo.count")).thenReturn("select count(foo) from Foo foo");
@@ -124,7 +123,7 @@ void considersNamedCountQuery() throws Exception {
void considersNamedCountOnStringQueryQuery() throws Exception {
QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND,
- VALUE_EXPRESSION_DELEGATE, new BeanFactoryQueryRewriterProvider(beanFactory), EscapeCharacter.DEFAULT);
+ CONFIG);
when(namedQueries.hasQuery("foo.count")).thenReturn(true);
when(namedQueries.getQuery("foo.count")).thenReturn("select count(foo) from Foo foo");
@@ -143,7 +142,7 @@ void considersNamedCountOnStringQueryQuery() throws Exception {
void prefersDeclaredQuery() throws Exception {
QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND,
- VALUE_EXPRESSION_DELEGATE, new BeanFactoryQueryRewriterProvider(beanFactory), EscapeCharacter.DEFAULT);
+ CONFIG);
Method method = UserRepository.class.getMethod("annotatedQueryWithQueryAndQueryName");
RepositoryMetadata metadata = new DefaultRepositoryMetadata(UserRepository.class);
@@ -156,7 +155,7 @@ void prefersDeclaredQuery() throws Exception {
void namedQueryWithSortShouldThrowIllegalStateException() throws NoSuchMethodException {
QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND,
- VALUE_EXPRESSION_DELEGATE, new BeanFactoryQueryRewriterProvider(beanFactory), EscapeCharacter.DEFAULT);
+ CONFIG);
Method method = UserRepository.class.getMethod("customNamedQuery", String.class, Sort.class);
RepositoryMetadata metadata = new DefaultRepositoryMetadata(UserRepository.class);
@@ -181,7 +180,7 @@ void noQueryShouldNotBeInvoked() {
void customQueryWithQuestionMarksShouldWork() throws NoSuchMethodException {
QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND,
- VALUE_EXPRESSION_DELEGATE, new BeanFactoryQueryRewriterProvider(beanFactory), EscapeCharacter.DEFAULT);
+ CONFIG);
Method namedMethod = UserRepository.class.getMethod("customQueryWithQuestionMarksAndNamedParam", String.class);
RepositoryMetadata namedMetadata = 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 9738c7843a..fa335ecee6 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
@@ -15,8 +15,7 @@
*/
package org.springframework.data.jpa.repository.query;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
+import static org.assertj.core.api.Assertions.*;
import java.util.HashMap;
import java.util.List;
@@ -25,6 +24,7 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
+
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
@@ -40,8 +40,11 @@
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.QueryRewriter;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
+import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.util.ReflectionTestUtils;
/**
* Unit tests for repository with {@link Query} and {@link QueryRewrite}.
@@ -54,6 +57,7 @@
class JpaQueryRewriteIntegrationTests {
@Autowired private UserRepositoryWithRewriter repository;
+ @Autowired private JpaRepositoryFactoryBean factoryBean;
// Results
static final String ORIGINAL_QUERY = "original query";
@@ -66,6 +70,14 @@ void setUp() {
results.clear();
}
+ @Test
+ void shouldConfigureQueryEnhancerSelector() {
+
+ JpaRepositoryFactory factory = (JpaRepositoryFactory) ReflectionTestUtils.getField(factoryBean, "factory");
+
+ assertThat(factory).extracting("queryEnhancerSelector").isInstanceOf(MyQueryEnhancerSelector.class);
+ }
+
@Test
void nativeQueryShouldHandleRewrites() {
@@ -222,7 +234,8 @@ private static String replaceAlias(String query, Sort sort) {
@ImportResource("classpath:infrastructure.xml")
@EnableJpaRepositories(considerNestedRepositories = true, basePackageClasses = UserRepositoryWithRewriter.class, //
includeFilters = @ComponentScan.Filter(value = { UserRepositoryWithRewriter.class },
- type = FilterType.ASSIGNABLE_TYPE))
+ type = FilterType.ASSIGNABLE_TYPE),
+ queryEnhancerSelector = MyQueryEnhancerSelector.class)
static class JpaRepositoryConfig {
@Bean
@@ -231,4 +244,10 @@ QueryRewriter queryRewriter() {
}
}
+
+ static class MyQueryEnhancerSelector extends QueryEnhancerSelector.DefaultQueryEnhancerSelector {
+ public MyQueryEnhancerSelector() {
+ super(QueryEnhancerFactories.fallback(), DefaultQueryEnhancerSelector.jpql());
+ }
+ }
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlParserQueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlParserQueryEnhancerUnitTests.java
index 8b6385e65d..32f9e965a9 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlParserQueryEnhancerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlParserQueryEnhancerUnitTests.java
@@ -32,7 +32,7 @@ QueryEnhancer createQueryEnhancer(DeclaredQuery query) {
assumeThat(query.isNativeQuery()).isFalse();
- return JpaQueryEnhancer.forJpql(query);
+ return JpaQueryEnhancer.forJpql(query.getQueryString());
}
@Override
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java
index 660f3c9a7d..acfa7d2b36 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java
@@ -832,6 +832,6 @@ private String projection(String query) {
}
private QueryEnhancer newParser(String query) {
- return JpaQueryEnhancer.forJpql(DeclaredQuery.of(query, false));
+ return JpaQueryEnhancer.forJpql(query);
}
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NamedQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NamedQueryUnitTests.java
index dadfd1083d..77a8496122 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NamedQueryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NamedQueryUnitTests.java
@@ -88,7 +88,7 @@ void rejectsPersistenceProviderIfIncapableOfExtractingQueriesAndPagebleBeingUsed
JpaQueryMethod queryMethod = new JpaQueryMethod(method, metadata, projectionFactory, extractor);
when(em.createNamedQuery(queryMethod.getNamedCountQueryName())).thenThrow(new IllegalArgumentException());
- assertThatExceptionOfType(QueryCreationException.class).isThrownBy(() -> NamedQuery.lookupFrom(queryMethod, em));
+ assertThatExceptionOfType(QueryCreationException.class).isThrownBy(() -> NamedQuery.lookupFrom(queryMethod, em, QueryEnhancerSelector.DEFAULT_SELECTOR));
}
@Test // DATAJPA-142
@@ -100,7 +100,7 @@ void doesNotRejectPersistenceProviderIfNamedCountQueryIsAvailable() {
TypedQuery countQuery = mock(TypedQuery.class);
when(em.createNamedQuery(eq(queryMethod.getNamedCountQueryName()), eq(Long.class))).thenReturn(countQuery);
- NamedQuery query = (NamedQuery) NamedQuery.lookupFrom(queryMethod, em);
+ NamedQuery query = (NamedQuery) NamedQuery.lookupFrom(queryMethod, em, QueryEnhancerSelector.DEFAULT_SELECTOR);
query.doCreateCountQuery(new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[1]));
verify(em, times(1)).createNamedQuery(queryMethod.getNamedCountQueryName(), Long.class);
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NativeJpaQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NativeJpaQueryUnitTests.java
index cf9dab51fb..fa44d2ca11 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NativeJpaQueryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NativeJpaQueryUnitTests.java
@@ -34,7 +34,6 @@
import org.springframework.data.domain.Sort;
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.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.RepositoryMetadata;
@@ -75,7 +74,8 @@ void shouldApplySorting() {
Query annotation = AnnotatedElementUtils.getMergedAnnotation(respositoryMethod, Query.class);
NativeJpaQuery query = new NativeJpaQuery(queryMethod, em, annotation.value(), annotation.countQuery(),
- QueryRewriter.IdentityQueryRewriter.INSTANCE, ValueExpressionDelegate.create());
+ new JpaQueryConfiguration(QueryRewriterProvider.simple(), QueryEnhancerSelector.DEFAULT_SELECTOR,
+ ValueExpressionDelegate.create(), EscapeCharacter.DEFAULT));
String sql = query.getSortedQueryString(Sort.by("foo", "bar"), queryMethod.getResultProcessor().getReturnedType());
assertThat(sql).isEqualTo("SELECT e FROM Employee e order by e.foo asc, e.bar asc");
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java
index 99b8a7a730..7456e047c2 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java
@@ -17,16 +17,7 @@
import static org.assertj.core.api.Assertions.*;
-import java.util.stream.Stream;
-
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-
-import org.springframework.data.jpa.repository.query.QueryEnhancerFactory.NativeQueryEnhancer;
-import org.springframework.data.jpa.util.ClassPathExclusions;
-import org.springframework.lang.Nullable;
/**
* Unit tests for {@link QueryEnhancerFactory}.
@@ -43,7 +34,7 @@ void createsParsingImplementationForNonNativeQuery() {
StringQuery query = new StringQuery("select new com.example.User(u.firstname) from User u", false);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(query);
+ QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(query).create(query);
assertThat(queryEnhancer) //
.isInstanceOf(JpaQueryEnhancer.class);
@@ -58,79 +49,10 @@ void createsJSqlImplementationForNativeQuery() {
StringQuery query = new StringQuery("select * from User", true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(query);
+ QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(query).create(query);
assertThat(queryEnhancer) //
.isInstanceOf(JSqlParserQueryEnhancer.class);
}
- @ParameterizedTest // GH-2989
- @MethodSource("nativeEnhancerSelectionArgs")
- void createsNativeImplementationAccordingToUserChoice(@Nullable String selection, NativeQueryEnhancer enhancer) {
-
- assertThat(NativeQueryEnhancer.JSQLPARSER_PRESENT).isTrue();
-
- withSystemProperty(NativeQueryEnhancer.NATIVE_PARSER_PROPERTY, selection, () -> {
- assertThat(NativeQueryEnhancer.select()).isEqualTo(enhancer);
- });
- }
-
- static Stream nativeEnhancerSelectionArgs() {
- return Stream.of(Arguments.of(null, NativeQueryEnhancer.JSQLPARSER), //
- Arguments.of("", NativeQueryEnhancer.JSQLPARSER), //
- Arguments.of("auto", NativeQueryEnhancer.JSQLPARSER), //
- Arguments.of("regex", NativeQueryEnhancer.REGEX), //
- Arguments.of("jsqlparser", NativeQueryEnhancer.JSQLPARSER));
- }
-
- @ParameterizedTest // GH-2989
- @MethodSource("nativeEnhancerExclusionSelectionArgs")
- @ClassPathExclusions(packages = { "net.sf.jsqlparser.parser" })
- void createsNativeImplementationAccordingWithoutJsqlParserToUserChoice(@Nullable String selection,
- NativeQueryEnhancer enhancer) {
-
- assertThat(NativeQueryEnhancer.JSQLPARSER_PRESENT).isFalse();
-
- withSystemProperty(NativeQueryEnhancer.NATIVE_PARSER_PROPERTY, selection, () -> {
- assertThat(NativeQueryEnhancer.select()).isEqualTo(enhancer);
- });
- }
-
- static Stream nativeEnhancerExclusionSelectionArgs() {
- return Stream.of(Arguments.of(null, NativeQueryEnhancer.REGEX), //
- Arguments.of("", NativeQueryEnhancer.REGEX), //
- Arguments.of("auto", NativeQueryEnhancer.REGEX), //
- Arguments.of("regex", NativeQueryEnhancer.REGEX), //
- Arguments.of("jsqlparser", NativeQueryEnhancer.JSQLPARSER));
- }
-
- @Test // GH-2989
- @ClassPathExclusions(packages = { "net.sf.jsqlparser.parser" })
- void selectedDefaultImplementationIfJsqlNotAvailable() {
-
- assertThat(NativeQueryEnhancer.JSQLPARSER_PRESENT).isFalse();
- assertThat(NativeQueryEnhancer.select()).isEqualTo(NativeQueryEnhancer.REGEX);
- }
-
- void withSystemProperty(String property, @Nullable String value, Runnable exeution) {
-
- String currentValue = System.getProperty(property);
- if (value != null) {
- System.setProperty(property, value);
- } else {
- System.clearProperty(property);
- }
- try {
- exeution.run();
- } finally {
- if (currentValue != null) {
- System.setProperty(property, currentValue);
- } else {
- System.clearProperty(property);
- }
- }
-
- }
-
-
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerTckTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerTckTests.java
index 077d469177..4b4bb8dfe0 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerTckTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerTckTests.java
@@ -35,8 +35,7 @@ abstract class QueryEnhancerTckTests {
@MethodSource("nativeCountQueries") // GH-2773
void shouldDeriveNativeCountQuery(String query, String expected) {
- DeclaredQuery declaredQuery = DeclaredQuery.of(query, true);
- QueryEnhancer enhancer = createQueryEnhancer(declaredQuery);
+ QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.ofNative(query));
String countQueryFor = enhancer.createCountQueryFor();
// lenient cleanup to allow for rendering variance
@@ -120,8 +119,7 @@ static Stream nativeCountQueries() {
@MethodSource("jpqlCountQueries")
void shouldDeriveJpqlCountQuery(String query, String expected) {
- DeclaredQuery declaredQuery = DeclaredQuery.of(query, false);
- QueryEnhancer enhancer = createQueryEnhancer(declaredQuery);
+ QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.ofJpql(query));
String countQueryFor = enhancer.createCountQueryFor(null);
assertThat(countQueryFor).isEqualToIgnoringCase(expected);
@@ -180,8 +178,7 @@ static Stream jpqlCountQueries() {
@MethodSource("nativeQueriesWithVariables")
void shouldDeriveNativeCountQueryWithVariable(String query, String expected) {
- DeclaredQuery declaredQuery = DeclaredQuery.of(query, true);
- QueryEnhancer enhancer = createQueryEnhancer(declaredQuery);
+ QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.ofNative(query));
String countQueryFor = enhancer.createCountQueryFor();
assertThat(countQueryFor).isEqualToIgnoringCase(expected);
@@ -211,6 +208,6 @@ void findProjectionClauseWithIncludedFrom() {
assertThat(createQueryEnhancer(query).getProjection()).isEqualTo("x, frommage, y");
}
- abstract QueryEnhancer createQueryEnhancer(DeclaredQuery declaredQuery);
+ abstract QueryEnhancer createQueryEnhancer(DeclaredQuery query);
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java
index 163a91dd95..66dbcca20d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java
@@ -78,7 +78,7 @@ void allowsShortJpaSyntax() {
@ParameterizedTest
@MethodSource("detectsAliasWithUCorrectlySource")
- void detectsAliasWithUCorrectly(DeclaredQuery query, String alias) {
+ void detectsAliasWithUCorrectly(IntrospectedQuery query, String alias) {
assumeThat(query.getQueryString()).as("JsqlParser does not support simple JPA syntax")
.doesNotStartWithIgnoringCase("from");
@@ -186,8 +186,7 @@ void preserveSourceQueryWhenAddingSort() {
true);
assertThat(getEnhancer(query).applySorting(Sort.by("name"), "p")) //
- .startsWithIgnoringCase(query.getQueryString())
- .endsWithIgnoringCase("ORDER BY p.name ASC");
+ .startsWithIgnoringCase(query.getQueryString()).endsWithIgnoringCase("ORDER BY p.name ASC");
}
@Test // GH-2812
@@ -433,7 +432,7 @@ void discoversAliasWithComplexFunction() {
assertThat(
QueryUtils.getFunctionAliases("select new MyDto(sum(case when myEntity.prop3=0 then 1 else 0 end) as myAlias")) //
- .contains("myAlias");
+ .contains("myAlias");
}
@Test // DATAJPA-1506
@@ -538,7 +537,7 @@ void detectsAliasWithGroupAndOrderByWithLineBreaks() {
@ParameterizedTest // DATAJPA-1679
@MethodSource("findProjectionClauseWithDistinctSource")
- void findProjectionClauseWithDistinct(DeclaredQuery query, String expected) {
+ void findProjectionClauseWithDistinct(IntrospectedQuery query, String expected) {
SoftAssertions.assertSoftly(sofly -> sofly.assertThat(getEnhancer(query).getProjection()).isEqualTo(expected));
}
@@ -633,7 +632,8 @@ void modifyingQueriesAreDetectedCorrectly() {
assertThat(modiQuery.hasConstructorExpression()).isEqualTo(constructorExpressionNotConsideringQueryType);
assertThat(countQueryForNotConsiderQueryType).isEqualToIgnoringCase(modifyingQuery);
- assertThat(QueryEnhancerFactory.forQuery(modiQuery).createCountQueryFor()).isEqualToIgnoringCase(modifyingQuery);
+ assertThat(QueryEnhancerFactory.forQuery(modiQuery).create(modiQuery).createCountQueryFor())
+ .isEqualToIgnoringCase(modifyingQuery);
}
@ParameterizedTest // GH-2593
@@ -641,7 +641,7 @@ void modifyingQueriesAreDetectedCorrectly() {
void insertStatementIsProcessedSameAsDefault(String insertQuery) {
StringQuery stringQuery = new StringQuery(insertQuery, true);
- QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+ QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery).create(stringQuery);
Sort sorting = Sort.by("day").descending();
@@ -696,8 +696,8 @@ private static void assertCountQuery(StringQuery originalQuery, String countQuer
assertThat(getEnhancer(originalQuery).createCountQueryFor()).isEqualToIgnoringCase(countQuery);
}
- private static QueryEnhancer getEnhancer(DeclaredQuery query) {
- return QueryEnhancerFactory.forQuery(query);
+ private static QueryEnhancer getEnhancer(IntrospectedQuery query) {
+ return QueryEnhancerFactory.forQuery(query).create(query);
}
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactoryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactoryUnitTests.java
index 4640443b99..34d3ab2397 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactoryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactoryUnitTests.java
@@ -52,7 +52,8 @@ void before() {
@Test // DATAJPA-1058
void noExceptionWhenQueryDoesNotContainNamedParameters() {
- setterFactory.create(binding);
+ setterFactory.create(binding,
+ EntityQuery.introspectJpql("from Employee e", QueryEnhancerSelector.DEFAULT_SELECTOR));
}
@Test // DATAJPA-1058
@@ -61,28 +62,14 @@ void exceptionWhenQueryContainNamedParametersAndMethodParametersAreNotNamed() {
when(binding.getOrigin()).thenReturn(ParameterOrigin.ofParameter("NamedParameter", 1));
assertThatExceptionOfType(IllegalStateException.class) //
- .isThrownBy(() -> setterFactory.create(binding
- )) //
+ .isThrownBy(() -> setterFactory.create(binding,
+ EntityQuery.introspectJpql("from Employee e where e.name = :NamedParameter",
+ QueryEnhancerSelector.DEFAULT_SELECTOR))) //
.withMessageContaining("Java 8") //
.withMessageContaining("@Param") //
.withMessageContaining("-parameters");
}
- @Test // DATAJPA-1281
- void exceptionWhenCriteriaQueryContainsInsufficientAmountOfParameters() {
-
- // no parameter present in the criteria query
- QueryParameterSetterFactory setterFactory = QueryParameterSetterFactory.forPartTreeQuery(parameters);
-
- // one argument present in the method signature
- when(binding.getRequiredPosition()).thenReturn(1);
- when(binding.getOrigin()).thenReturn(ParameterOrigin.ofParameter(null, 1));
-
- assertThatExceptionOfType(IllegalArgumentException.class) //
- .isThrownBy(() -> setterFactory.create(binding)) //
- .withMessage("At least 1 parameter(s) provided but only 0 parameter(s) present in query");
- }
-
@Test // DATAJPA-1281
void exceptionWhenBasicQueryContainsInsufficientAmountOfParameters() {
@@ -94,7 +81,10 @@ void exceptionWhenBasicQueryContainsInsufficientAmountOfParameters() {
when(binding.getOrigin()).thenReturn(ParameterOrigin.ofParameter(null, 1));
assertThatExceptionOfType(IllegalArgumentException.class) //
- .isThrownBy(() -> setterFactory.create(binding)) //
+ .isThrownBy(
+ () -> setterFactory.create(binding,
+ EntityQuery.introspectJpql("from Employee e where e.name = ?1",
+ QueryEnhancerSelector.DEFAULT_SELECTOR))) //
.withMessage("At least 1 parameter(s) provided but only 0 parameter(s) present in query");
}
}
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 5d2beb3d9b..e60a1aac2c 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
@@ -46,7 +46,6 @@
import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.jpa.repository.NativeQuery;
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;
@@ -75,6 +74,9 @@
@MockitoSettings(strictness = Strictness.LENIENT)
class SimpleJpaQueryUnitTests {
+ private static final JpaQueryConfiguration CONFIG = new JpaQueryConfiguration(QueryRewriterProvider.simple(),
+ QueryEnhancerSelector.DEFAULT_SELECTOR, ValueExpressionDelegate.create(), EscapeCharacter.DEFAULT);
+
private static final String USER_QUERY = "select u from User u";
private JpaQueryMethod method;
@@ -119,8 +121,7 @@ void prefersDeclaredCountQueryOverCreatingOne() throws Exception {
extractor);
when(em.createQuery("foo", Long.class)).thenReturn(typedQuery);
- SimpleJpaQuery jpaQuery = new SimpleJpaQuery(method, em, "select u from User u", null,
- QueryRewriter.IdentityQueryRewriter.INSTANCE, ValueExpressionDelegate.create());
+ SimpleJpaQuery jpaQuery = new SimpleJpaQuery(method, em, "select u from User u", null, CONFIG);
assertThat(jpaQuery.createCountQuery(new JpaParametersParameterAccessor(method.getParameters(), new Object[] {})))
.isEqualTo(typedQuery);
@@ -134,8 +135,7 @@ void doesNotApplyPaginationToCountQuery() throws Exception {
Method method = UserRepository.class.getMethod("findAllPaged", Pageable.class);
JpaQueryMethod queryMethod = new JpaQueryMethod(method, metadata, factory, extractor);
- AbstractJpaQuery jpaQuery = new SimpleJpaQuery(queryMethod, em, "select u from User u", null,
- QueryRewriter.IdentityQueryRewriter.INSTANCE, ValueExpressionDelegate.create());
+ AbstractJpaQuery jpaQuery = new SimpleJpaQuery(queryMethod, em, "select u from User u", null, CONFIG);
jpaQuery.createCountQuery(
new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[] { PageRequest.of(1, 10) }));
@@ -149,9 +149,8 @@ void discoversNativeQuery() throws Exception {
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, QueryRewriter.IdentityQueryRewriter.INSTANCE,
- ValueExpressionDelegate.create());
+ AbstractJpaQuery jpaQuery = JpaQueryLookupStrategy.DeclaredQueryLookupStrategy.createStringQuery(queryMethod, em,
+ queryMethod.getAnnotatedQuery(), null, CONFIG);
assertThat(jpaQuery).isInstanceOf(NativeJpaQuery.class);
@@ -169,9 +168,8 @@ void discoversNativeQueryFromNativeQueryInterface() throws Exception {
Method method = SampleRepository.class.getMethod("findByLastnameNativeAnnotation", String.class);
JpaQueryMethod queryMethod = new JpaQueryMethod(method, metadata, factory, extractor);
- AbstractJpaQuery jpaQuery = JpaQueryFactory.INSTANCE.fromMethodWithQueryString(queryMethod, em,
- queryMethod.getAnnotatedQuery(), null, QueryRewriter.IdentityQueryRewriter.INSTANCE,
- ValueExpressionDelegate.create());
+ AbstractJpaQuery jpaQuery = JpaQueryLookupStrategy.DeclaredQueryLookupStrategy.createStringQuery(queryMethod, em,
+ queryMethod.getAnnotatedQuery(), null, CONFIG);
assertThat(jpaQuery).isInstanceOf(NativeJpaQuery.class);
@@ -239,10 +237,11 @@ void allowsCountQueryUsingParametersNotInOriginalQuery() throws Exception {
when(em.createNativeQuery(anyString())).thenReturn(query);
AbstractJpaQuery jpaQuery = createJpaQuery(
- SampleRepository.class.getMethod("findAllWithBindingsOnlyInCountQuery", String.class, Pageable.class), Optional.empty());
+ SampleRepository.class.getMethod("findAllWithBindingsOnlyInCountQuery", String.class, Pageable.class),
+ Optional.empty());
jpaQuery.doCreateCountQuery(new JpaParametersParameterAccessor(jpaQuery.getQueryMethod().getParameters(),
- new Object[]{"data", PageRequest.of(0, 10)}));
+ new Object[] { "data", PageRequest.of(0, 10) }));
ArgumentCaptor queryStringCaptor = ArgumentCaptor.forClass(String.class);
verify(em).createQuery(queryStringCaptor.capture(), eq(Long.class));
@@ -283,8 +282,7 @@ void resolvesExpressionInCountQuery() throws Exception {
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", QueryRewriter.IdentityQueryRewriter.INSTANCE,
- ValueExpressionDelegate.create());
+ "select count(u.id) from #{#entityName} u", CONFIG);
jpaQuery.createCountQuery(
new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[] { PageRequest.of(1, 10) }));
@@ -296,16 +294,18 @@ private AbstractJpaQuery createJpaQuery(Method method) {
return createJpaQuery(method, null);
}
- private AbstractJpaQuery createJpaQuery(JpaQueryMethod queryMethod, @Nullable String queryString, @Nullable String countQueryString) {
+ private AbstractJpaQuery createJpaQuery(JpaQueryMethod queryMethod, @Nullable String queryString,
+ @Nullable String countQueryString) {
- return JpaQueryFactory.INSTANCE.fromMethodWithQueryString(queryMethod, em, queryString, countQueryString,
- QueryRewriter.IdentityQueryRewriter.INSTANCE, ValueExpressionDelegate.create());
+ return JpaQueryLookupStrategy.DeclaredQueryLookupStrategy.createStringQuery(queryMethod, em, queryString,
+ countQueryString, CONFIG);
}
private AbstractJpaQuery createJpaQuery(Method method, @Nullable Optional countQueryString) {
JpaQueryMethod queryMethod = new JpaQueryMethod(method, metadata, factory, extractor);
- return createJpaQuery(queryMethod, queryMethod.getAnnotatedQuery(), countQueryString == null ? null : countQueryString.orElse(queryMethod.getCountQuery()));
+ return createJpaQuery(queryMethod, queryMethod.getAnnotatedQuery(),
+ countQueryString == null ? null : countQueryString.orElse(queryMethod.getCountQuery()));
}
interface SampleRepository {
@@ -337,8 +337,8 @@ interface SampleRepository {
@Query(value = "select u from #{#entityName} u", countQuery = "select count(u.id) from #{#entityName} u")
List findAllWithExpressionInCountQuery(Pageable pageable);
-
- @Query(value = "select u from User u", countQuery = "select count(u.id) from #{#entityName} u where u.name = :#{#arg0}")
+ @Query(value = "select u from User u",
+ countQuery = "select count(u.id) from #{#entityName} u where u.name = :#{#arg0}")
List findAllWithBindingsOnlyInCountQuery(String arg0, Pageable pageable);
// Typo in named parameter
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java
index 4db398991d..e0dfb12e64 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java
@@ -715,12 +715,14 @@ void usingGreaterThanWithNamedParameter() {
void checkNumberOfNamedParameters(String query, int expectedSize, String label, boolean nativeQuery) {
- DeclaredQuery declaredQuery = DeclaredQuery.of(query, nativeQuery);
+ EntityQuery introspectedQuery = nativeQuery
+ ? EntityQuery.introspectNativeQuery(query, QueryEnhancerSelector.DEFAULT_SELECTOR)
+ : EntityQuery.introspectJpql(query, QueryEnhancerSelector.DEFAULT_SELECTOR);
- assertThat(declaredQuery.hasNamedParameter()) //
+ assertThat(introspectedQuery.hasNamedParameter()) //
.describedAs("hasNamed Parameter " + label) //
.isEqualTo(expectedSize > 0);
- assertThat(declaredQuery.getParameterBindings()) //
+ assertThat(introspectedQuery.getParameterBindings()) //
.describedAs("parameterBindings " + label) //
.hasSize(expectedSize);
}