diff --git a/spring-data-jpa/src/jmh/java/org/springframework/data/jpa/repository/query/HqlParserBenchmarks.java b/spring-data-jpa/src/jmh/java/org/springframework/data/jpa/repository/query/HqlParserBenchmarks.java index 482c4454fa..ce970cb57d 100644 --- a/spring-data-jpa/src/jmh/java/org/springframework/data/jpa/repository/query/HqlParserBenchmarks.java +++ b/spring-data-jpa/src/jmh/java/org/springframework/data/jpa/repository/query/HqlParserBenchmarks.java @@ -55,8 +55,8 @@ OR TREAT(p AS SmallProject).name LIKE 'Persist%' OR p.description LIKE "cost overrun" """; - query = DeclaredQuery.of(s, false); - enhancer = QueryEnhancerFactory.forQuery(query); + query = DeclaredQuery.ofJpql(s); + enhancer = QueryEnhancerFactory.forQuery(query).create(query); } } diff --git a/spring-data-jpa/src/jmh/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerBenchmarks.java b/spring-data-jpa/src/jmh/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerBenchmarks.java index 724a417353..af2f0446a5 100644 --- a/spring-data-jpa/src/jmh/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerBenchmarks.java +++ b/spring-data-jpa/src/jmh/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerBenchmarks.java @@ -56,7 +56,7 @@ public void doSetup() throws IOException { select SOME_COLUMN from SOME_OTHER_TABLE where REPORTING_DATE = :REPORTING_DATE union select SOME_COLUMN from SOME_OTHER_OTHER_TABLE"""; - enhancer = new JSqlParserQueryEnhancer(DeclaredQuery.of(s, true)); + enhancer = new JSqlParserQueryEnhancer(DeclaredQuery.ofNative(s)); } } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java index 901bedea3f..3e34227e4e 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java @@ -48,7 +48,7 @@ */ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery { - private final IntrospectedQuery query; + private final EntityQuery query; private final Lazy countQuery; private final ValueExpressionDelegate valueExpressionDelegate; private final QueryParameterSetter.QueryMetadataCache metadataCache = new QueryParameterSetter.QueryMetadataCache(); @@ -65,33 +65,27 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery { * @param em must not be {@literal null}. * @param queryString must not be {@literal null}. * @param countQueryString must not be {@literal null}. - * @param queryRewriter must not be {@literal null}. - * @param valueExpressionDelegate must not be {@literal null}. * @param queryConfiguration must not be {@literal null}. */ public AbstractStringBasedJpaQuery(JpaQueryMethod method, EntityManager em, String queryString, - @Nullable String countQueryString, QueryRewriter queryRewriter, - ValueExpressionDelegate valueExpressionDelegate, JpaQueryConfiguration queryConfiguration) { + @Nullable String countQueryString, JpaQueryConfiguration queryConfiguration) { super(method, em); Assert.hasText(queryString, "Query string must not be null or empty"); - Assert.notNull(valueExpressionDelegate, "ValueExpressionDelegate must not be null"); - Assert.notNull(queryRewriter, "QueryRewriter must not be null"); + Assert.notNull(queryConfiguration, "JpaQueryConfiguration must not be null"); - this.valueExpressionDelegate = valueExpressionDelegate; + this.valueExpressionDelegate = queryConfiguration.getValueExpressionDelegate(); this.valueExpressionContextProvider = valueExpressionDelegate.createValueContextProvider(method.getParameters()); this.query = ExpressionBasedStringQuery.create(queryString, method, queryConfiguration); this.countQuery = Lazy.of(() -> { if (StringUtils.hasText(countQueryString)) { - - return ExpressionBasedStringQuery.create(countQueryString, method, queryConfiguration); - + return ExpressionBasedStringQuery.create(countQueryString, method, queryConfiguration); } - return query.deriveCountQuery(method.getCountQueryProjection()); + return this.query.deriveCountQuery(method.getCountQueryProjection()); }); this.countParameterBinder = Lazy.of(() -> { @@ -107,7 +101,7 @@ public AbstractStringBasedJpaQuery(JpaQueryMethod method, EntityManager em, Stri this.querySortRewriter = NoOpQuerySortRewriter.INSTANCE; } - Assert.isTrue(method.isNativeQuery() || !query.usesJdbcStyleParameters(), + Assert.isTrue(method.isNativeQuery() || !this.query.usesJdbcStyleParameters(), "JDBC style parameters (?) are not supported for JPA queries"); } @@ -162,7 +156,7 @@ protected Query doCreateCountQuery(JpaParametersParameterAccessor accessor) { /** * @return the query */ - public IntrospectedQuery getQuery() { + public EntityQuery getQuery() { return query; } @@ -210,16 +204,14 @@ protected String potentiallyRewriteQuery(String originalQuery, Sort sort, @Nulla } String applySorting(CachableQuery cachableQuery) { - - return QueryEnhancerFactory.forQuery(cachableQuery.getDeclaredQuery()).applySorting(cachableQuery.getSort(), - cachableQuery.getAlias()); + return cachableQuery.getDeclaredQuery().applySorting(cachableQuery.getSort()); } /** * Query Sort Rewriter interface. */ interface QuerySortRewriter { - String getSorted(IntrospectedQuery query, Sort sort); + String getSorted(EntityQuery query, Sort sort); } /** @@ -228,7 +220,7 @@ interface QuerySortRewriter { enum NoOpQuerySortRewriter implements QuerySortRewriter { INSTANCE; - public String getSorted(IntrospectedQuery query, Sort sort) { + public String getSorted(EntityQuery query, Sort sort) { if (sort.isSorted()) { throw new UnsupportedOperationException("NoOpQueryCache does not support sorting"); @@ -247,7 +239,7 @@ class CachingQuerySortRewriter implements QuerySortRewriter { AbstractStringBasedJpaQuery.this::applySorting); @Override - public String getSorted(IntrospectedQuery query, Sort sort) { + public String getSorted(EntityQuery query, Sort sort) { if (sort.isUnsorted()) { return query.getQueryString(); @@ -266,18 +258,18 @@ public String getSorted(IntrospectedQuery query, Sort sort) { */ static class CachableQuery { - private final IntrospectedQuery introspectedQuery; + private final EntityQuery introspectedQuery; private final String queryString; private final Sort sort; - CachableQuery(IntrospectedQuery query, Sort sort) { + CachableQuery(EntityQuery query, Sort sort) { this.introspectedQuery = query; this.queryString = query.getQueryString(); this.sort = sort; } - IntrospectedQuery getDeclaredQuery() { + EntityQuery getDeclaredQuery() { return introspectedQuery; } @@ -285,11 +277,6 @@ Sort getSort() { return sort; } - @Nullable - String getAlias() { - return introspectedQuery.getAlias(); - } - @Override public boolean equals(Object o) { diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DeclaredQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DeclaredQuery.java index 6d1a691a33..e05e852781 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DeclaredQuery.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DeclaredQuery.java @@ -28,7 +28,7 @@ public interface DeclaredQuery { * @param query the JPQL query string. * @return */ - static DeclaredQuery jpql(String query) { + static DeclaredQuery ofJpql(String query) { return new DefaultDeclaredQuery(query, false); } @@ -38,7 +38,7 @@ static DeclaredQuery jpql(String query) { * @param query the native query string. * @return */ - static DeclaredQuery nativeQuery(String query) { + static DeclaredQuery ofNative(String query) { return new DefaultDeclaredQuery(query, true); } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DefaultDeclaredQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DefaultDeclaredQuery.java index 4ce3f4a136..a24512a994 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DefaultDeclaredQuery.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DefaultDeclaredQuery.java @@ -30,10 +30,12 @@ class DefaultDeclaredQuery implements DeclaredQuery { this.nativeQuery = nativeQuery; } + @Override public String getQueryString() { return query; } + @Override public boolean isNativeQuery() { return nativeQuery; } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EmptyIntrospectedQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EmptyIntrospectedQuery.java index 8b6041174f..8078a1b4c8 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EmptyIntrospectedQuery.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EmptyIntrospectedQuery.java @@ -18,6 +18,7 @@ import java.util.Collections; import java.util.List; +import org.springframework.data.domain.Sort; import org.springframework.lang.Nullable; /** @@ -26,12 +27,12 @@ * @author Jens Schauder * @since 2.0.3 */ -class EmptyIntrospectedQuery implements IntrospectedQuery { +class EmptyIntrospectedQuery implements EntityQuery { /** * An implementation implementing the NULL-Object pattern for situations where there is no query. */ - static final IntrospectedQuery EMPTY_QUERY = new EmptyIntrospectedQuery(); + static final EntityQuery EMPTY_QUERY = new EmptyIntrospectedQuery(); @Override public boolean hasNamedParameter() { @@ -48,11 +49,6 @@ public boolean isNativeQuery() { return false; } - @Override - public String getAlias() { - return null; - } - @Override public boolean hasConstructorExpression() { return false; @@ -73,6 +69,11 @@ public IntrospectedQuery deriveCountQuery(@Nullable String countQueryProjection) return EMPTY_QUERY; } + @Override + public String applySorting(Sort sort) { + return ""; + } + @Override public boolean usesJdbcStyleParameters() { return false; diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EntityQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EntityQuery.java new file mode 100644 index 0000000000..8d193f8739 --- /dev/null +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EntityQuery.java @@ -0,0 +1,105 @@ +/* + * Copyright 2018-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.domain.Sort; +import org.springframework.lang.Nullable; +import org.springframework.util.ObjectUtils; + +/** + * A wrapper for a String representation of a query offering information about the query. + * + * @author Jens Schauder + * @author Diego Krupitza + * @since 2.0.3 + */ +interface EntityQuery extends IntrospectedQuery { + + /** + * Creates a DeclaredQuery for a JPQL query. + * + * @param query the JPQL query string. + * @return + */ + static EntityQuery introspectJpql(String query, QueryEnhancerFactory queryEnhancer) { + return ObjectUtils.isEmpty(query) ? EmptyIntrospectedQuery.EMPTY_QUERY + : new StringQuery(query, false, queryEnhancer); + } + + /** + * Creates a DeclaredQuery for a JPQL query. + * + * @param query the JPQL query string. + * @return + */ + static EntityQuery introspectJpql(String query, QueryEnhancerSelector selector) { + return ObjectUtils.isEmpty(query) ? EmptyIntrospectedQuery.EMPTY_QUERY : new StringQuery(query, false, selector); + } + + /** + * Creates a DeclaredQuery for a native query. + * + * @param query the native query string. + * @return + */ + static EntityQuery introspectNativeQuery(String query, QueryEnhancerFactory queryEnhancer) { + return ObjectUtils.isEmpty(query) ? EmptyIntrospectedQuery.EMPTY_QUERY + : new StringQuery(query, true, queryEnhancer); + } + + /** + * Creates a DeclaredQuery for a native query. + * + * @param query the native query string. + * @return + */ + static EntityQuery introspectNativeQuery(String query, QueryEnhancerSelector selector) { + return ObjectUtils.isEmpty(query) ? EmptyIntrospectedQuery.EMPTY_QUERY : new StringQuery(query, true, selector); + } + + /** + * Returns whether the query is using a constructor expression. + * + * @since 1.10 + */ + boolean hasConstructorExpression(); + + /** + * Returns whether the query uses the default projection, i.e. returns the main alias defined for the query. + */ + boolean isDefaultProjection(); + + /** + * Creates a new {@literal DeclaredQuery} representing a count query, i.e. a query returning the number of rows to be + * expected from the original query, either derived from the query wrapped by this instance or from the information + * passed as arguments. + * + * @param countQueryProjection an optional return type for the query. + * @return a new {@literal DeclaredQuery} instance. + */ + IntrospectedQuery deriveCountQuery(@Nullable String countQueryProjection); + + String applySorting(Sort sort); + + /** + * @return whether paging is implemented in the query itself, e.g. using SpEL expressions. + * @since 2.0.6 + */ + default boolean usesPaging() { + return false; + } + +} diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java index 55b3b19bee..e2286e69c0 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java @@ -67,20 +67,6 @@ class ExpressionBasedStringQuery extends StringQuery { selector); } - /** - * Creates an {@link ExpressionBasedStringQuery} from a given {@link DeclaredQuery}. - * - * @param query the original query. Must not be {@literal null}. - * @param metadata the {@link JpaEntityMetadata} for the given entity. Must not be {@literal null}. - * @param parser Parser for resolving SpEL expressions. Must not be {@literal null}. - * @param nativeQuery is a given query native or not - * @return A query supporting SpEL expressions. - */ - static ExpressionBasedStringQuery from(DeclaredQuery query, JpaEntityMetadata metadata, - ValueExpressionParser parser, boolean nativeQuery) { - return new ExpressionBasedStringQuery(query.getQueryString(), metadata, parser, nativeQuery); - } - /** * @param query, the query expression potentially containing a SpEL expression. Must not be {@literal null}. * @param metadata the {@link JpaEntityMetadata} for the given entity. Must not be {@literal null}. @@ -125,8 +111,9 @@ private static boolean containsExpression(String query) { return query.contains(ENTITY_NAME_VARIABLE_EXPRESSION); } - public static IntrospectedQuery create(String query, JpaQueryMethod method, JpaQueryConfiguration queryContext) { - return new ExpressionBasedStringQuery(query, method.getEntityInformation(), queryContext.getParser(), + public static EntityQuery create(String query, JpaQueryMethod method, JpaQueryConfiguration queryContext) { + return new ExpressionBasedStringQuery(query, method.getEntityInformation(), + queryContext.getValueExpressionDelegate().getValueExpressionParser(), method.isNativeQuery(), queryContext.getSelector()); } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/IntrospectedQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/IntrospectedQuery.java index 9f535c1ba3..427dbcc03b 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/IntrospectedQuery.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/IntrospectedQuery.java @@ -17,9 +17,6 @@ import java.util.List; -import org.springframework.lang.Nullable; -import org.springframework.util.ObjectUtils; - /** * A wrapper for a String representation of a query offering information about the query. * @@ -29,50 +26,11 @@ */ interface IntrospectedQuery extends DeclaredQuery { - /** - * Creates a {@literal DeclaredQuery} from a query {@literal String}. - * - * @param query might be {@literal null} or empty. - * @param nativeQuery is a given query is native or not - * @return a {@literal DeclaredQuery} instance even for a {@literal null} or empty argument. - */ - static IntrospectedQuery of(@Nullable String query, boolean nativeQuery) { - return of(query, nativeQuery, QueryEnhancerSelector.DEFAULT_SELECTOR); - } - - /** - * Creates a {@literal DeclaredQuery} from a query {@literal String}. - * - * @param query might be {@literal null} or empty. - * @param nativeQuery is a given query is native or not - * @param selector - * @return a {@literal DeclaredQuery} instance even for a {@literal null} or empty argument. - */ - static IntrospectedQuery of(@Nullable String query, boolean nativeQuery, QueryEnhancerSelector selector) { - return ObjectUtils.isEmpty(query) ? EmptyIntrospectedQuery.EMPTY_QUERY - : new StringQuery(query, nativeQuery, selector); - } - /** * @return whether the underlying query has at least one named parameter. */ boolean hasNamedParameter(); - /** - * Returns the main alias used in the query. - * - * @return the alias - */ - @Nullable - String getAlias(); - - /** - * Returns whether the query is using a constructor expression. - * - * @since 1.10 - */ - boolean hasConstructorExpression(); - /** * Returns whether the query uses the default projection, i.e. returns the main alias defined for the query. */ @@ -83,24 +41,6 @@ static IntrospectedQuery of(@Nullable String query, boolean nativeQuery, QueryEn */ List getParameterBindings(); - /** - * Creates a new {@literal DeclaredQuery} representing a count query, i.e. a query returning the number of rows to be - * expected from the original query, either derived from the query wrapped by this instance or from the information - * passed as arguments. - * - * @param countQueryProjection an optional return type for the query. - * @return a new {@literal DeclaredQuery} instance. - */ - IntrospectedQuery deriveCountQuery(@Nullable String countQueryProjection); - - /** - * @return whether paging is implemented in the query itself, e.g. using SpEL expressions. - * @since 2.0.6 - */ - default boolean usesPaging() { - return false; - } - /** * Returns whether the query uses JDBC style parameters, i.e. parameters denoted by a simple ? without any index or * name. diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryConfiguration.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryConfiguration.java index 5100131fdf..7bce8dc8f7 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryConfiguration.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryConfiguration.java @@ -16,8 +16,7 @@ package org.springframework.data.jpa.repository.query; import org.springframework.data.jpa.repository.QueryRewriter; -import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; -import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.data.repository.query.ValueExpressionDelegate; /** * Configuration object holding configuration information for JPA queries within a repository. @@ -29,18 +28,15 @@ public class JpaQueryConfiguration { private final QueryRewriterProvider queryRewriter; private final QueryEnhancerSelector selector; private final EscapeCharacter escapeCharacter; - private final QueryMethodEvaluationContextProvider evaluationContextProvider; - private final SpelExpressionParser parser; + private final ValueExpressionDelegate valueExpressionDelegate; public JpaQueryConfiguration(QueryRewriterProvider queryRewriter, QueryEnhancerSelector selector, - QueryMethodEvaluationContextProvider evaluationContextProvider, EscapeCharacter escapeCharacter, - SpelExpressionParser parser) { + ValueExpressionDelegate valueExpressionDelegate, EscapeCharacter escapeCharacter) { this.queryRewriter = queryRewriter; this.selector = selector; this.escapeCharacter = escapeCharacter; - this.evaluationContextProvider = evaluationContextProvider; - this.parser = parser; + this.valueExpressionDelegate = valueExpressionDelegate; } public QueryRewriter getQueryRewriter(JpaQueryMethod queryMethod) { @@ -55,11 +51,7 @@ public EscapeCharacter getEscapeCharacter() { return escapeCharacter; } - public QueryMethodEvaluationContextProvider getEvaluationContextProvider() { - return evaluationContextProvider; - } - - public SpelExpressionParser getParser() { - return parser; + public ValueExpressionDelegate getValueExpressionDelegate() { + return valueExpressionDelegate; } } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java index 9b8f8b3356..8c376c44b0 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java @@ -22,7 +22,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.core.env.StandardEnvironment; import org.springframework.data.jpa.repository.Query; import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.repository.core.NamedQueries; @@ -31,11 +30,7 @@ import org.springframework.data.repository.query.QueryLookupStrategy; import org.springframework.data.repository.query.QueryLookupStrategy.Key; import org.springframework.data.repository.query.QueryMethod; -import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; -import org.springframework.data.repository.query.QueryMethodValueEvaluationContextAccessor; import org.springframework.data.repository.query.RepositoryQuery; -import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.data.repository.query.ValueExpressionDelegate; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -132,9 +127,7 @@ protected RepositoryQuery resolveQuery(JpaQueryMethod method, JpaQueryConfigurat * @author Thomas Darimont * @author Jens Schauder */ - private static class DeclaredQueryLookupStrategy extends AbstractQueryLookupStrategy { - - private final ValueExpressionDelegate valueExpressionDelegate; + static class DeclaredQueryLookupStrategy extends AbstractQueryLookupStrategy { /** * Creates a new {@link DeclaredQueryLookupStrategy}. @@ -144,11 +137,9 @@ private static class DeclaredQueryLookupStrategy extends AbstractQueryLookupStra * @param configuration must not be {@literal null}. */ public DeclaredQueryLookupStrategy(EntityManager em, JpaQueryMethodFactory queryMethodFactory, - ValueExpressionDelegate delegate, QueryRewriterProvider queryRewriterProvider) { - - super(em, queryMethodFactory, queryRewriterProvider); + JpaQueryConfiguration configuration) { - this.valueExpressionDelegate = delegate; + super(em, queryMethodFactory, configuration); } @Override @@ -166,14 +157,14 @@ protected RepositoryQuery resolveQuery(JpaQueryMethod method, JpaQueryConfigurat "Query method %s is annotated with both, a query and a query name; Using the declared query", method)); } - return JpaQueryFactory.INSTANCE.fromMethodWithQueryString(method, em, method.getRequiredAnnotatedQuery(), - getCountQuery(method, namedQueries, em), queryRewriter, valueExpressionDelegate); + return createStringQuery(method, em, method.getRequiredAnnotatedQuery(), + getCountQuery(method, namedQueries, em), configuration); } String name = method.getNamedQueryName(); if (namedQueries.hasQuery(name)) { - return JpaQueryFactory.INSTANCE.fromMethodWithQueryString(method, em, namedQueries.getQuery(name), - getCountQuery(method, namedQueries, em), queryRewriter, valueExpressionDelegate); + return createStringQuery(method, em, namedQueries.getQuery(name), getCountQuery(method, namedQueries, em), + configuration); } RepositoryQuery query = NamedQuery.lookupFrom(method, em, configuration.getSelector()); @@ -294,46 +285,6 @@ protected RepositoryQuery resolveQuery(JpaQueryMethod method, JpaQueryConfigurat } } - /** - * Creates a {@link QueryLookupStrategy} for the given {@link EntityManager} and {@link Key}. - * - * @param em must not be {@literal null}. - * @param queryMethodFactory must not be {@literal null}. - * @param key may be {@literal null}. - * @param evaluationContextProvider must not be {@literal null}. - * @param escape must not be {@literal null}. - * @deprecated since 3.4, use - * {@link #create(EntityManager, JpaQueryMethodFactory, Key, ValueExpressionDelegate, QueryRewriterProvider, EscapeCharacter)} - * instead. - */ - @Deprecated(since = "3.4") - public static QueryLookupStrategy create(EntityManager em, JpaQueryMethodFactory queryMethodFactory, - @Nullable Key key, QueryMethodEvaluationContextProvider evaluationContextProvider, - QueryRewriterProvider queryRewriterProvider, EscapeCharacter escape) { - return create(em, queryMethodFactory, key, - new ValueExpressionDelegate(new QueryMethodValueEvaluationContextAccessor(new StandardEnvironment(), - evaluationContextProvider.getEvaluationContextProvider()), ValueExpressionDelegate.create()), - queryRewriterProvider, escape); - } - - /** - * Creates a {@link QueryLookupStrategy} for the given {@link EntityManager} and {@link Key}. - * - * @param em must not be {@literal null}. - * @param queryMethodFactory must not be {@literal null}. - * @param key may be {@literal null}. - * @param delegate must not be {@literal null}. - * @param queryRewriterProvider must not be {@literal null}. - * @param escape must not be {@literal null}. - */ - public static QueryLookupStrategy create(EntityManager em, JpaQueryMethodFactory queryMethodFactory, - @Nullable Key key, ValueExpressionDelegate delegate, QueryRewriterProvider queryRewriterProvider, - EscapeCharacter escape) { - - return create(em, queryMethodFactory, key, new JpaQueryConfiguration(queryRewriterProvider, - QueryEnhancerSelector.DEFAULT_SELECTOR, evaluationContextProvider, escape, new SpelExpressionParser())); - } - /** * Creates a {@link QueryLookupStrategy} for the given {@link EntityManager} and {@link Key}. * @@ -349,13 +300,11 @@ public static QueryLookupStrategy create(EntityManager em, JpaQueryMethodFactory Assert.notNull(configuration, "JpaQueryConfiguration must not be null"); return switch (key != null ? key : Key.CREATE_IF_NOT_FOUND) { - case CREATE -> new CreateQueryLookupStrategy(em, queryMethodFactory, queryRewriterProvider, escape); - case USE_DECLARED_QUERY -> - new DeclaredQueryLookupStrategy(em, queryMethodFactory, delegate, queryRewriterProvider); + case CREATE -> new CreateQueryLookupStrategy(em, queryMethodFactory, configuration); + case USE_DECLARED_QUERY -> new DeclaredQueryLookupStrategy(em, queryMethodFactory, configuration); case CREATE_IF_NOT_FOUND -> new CreateIfNotFoundQueryLookupStrategy(em, queryMethodFactory, - new CreateQueryLookupStrategy(em, queryMethodFactory, queryRewriterProvider, escape), - new DeclaredQueryLookupStrategy(em, queryMethodFactory, delegate, queryRewriterProvider), - queryRewriterProvider); + new CreateQueryLookupStrategy(em, queryMethodFactory, configuration), + new DeclaredQueryLookupStrategy(em, queryMethodFactory, configuration), configuration); default -> throw new IllegalArgumentException(String.format("Unsupported query lookup strategy %s", key)); }; } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java index 863e71f14b..1e57f6e0a5 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java @@ -23,7 +23,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.data.jpa.provider.QueryExtractor; import org.springframework.data.repository.query.Parameters; import org.springframework.data.repository.query.QueryCreationException; @@ -53,7 +52,7 @@ final class NamedQuery extends AbstractJpaQuery { private final String countQueryName; private final @Nullable String countProjection; private final boolean namedCountQueryIsPresent; - private final Lazy introspectedQuery; + private final Lazy entityQuery; private final QueryParameterSetter.QueryMetadataCache metadataCache; /** @@ -93,11 +92,14 @@ private NamedQuery(JpaQueryMethod method, EntityManager em, QueryEnhancerSelecto } String queryString = extractor.extractQueryString(query); - org.springframework.data.jpa.repository.Query queryAnnotation = AnnotatedElementUtils - .findMergedAnnotation(method.getMethod(), org.springframework.data.jpa.repository.Query.class); - this.introspectedQuery = Lazy - .of(() -> IntrospectedQuery.of(queryString, method.isNativeQuery() || query.toString().contains("NativeQuery"))); + // TODO: What is queryString is null? + if (method.isNativeQuery() || (query != null && query.toString().contains("NativeQuery"))) { + this.entityQuery = Lazy.of(() -> EntityQuery.introspectNativeQuery(queryString, selector)); + } else { + this.entityQuery = Lazy.of(() -> EntityQuery.introspectJpql(queryString, selector)); + } + this.metadataCache = new QueryParameterSetter.QueryMetadataCache(); } @@ -191,7 +193,7 @@ protected TypedQuery doCreateCountQuery(JpaParametersParameterAccessor acc } else { - String countQueryString = introspectedQuery.get().deriveCountQuery(countProjection).getQueryString(); + String countQueryString = entityQuery.get().deriveCountQuery(countProjection).getQueryString(); cacheKey = countQueryString; countQuery = em.createQuery(countQueryString, Long.class); } @@ -223,7 +225,7 @@ protected Class getTypeToRead(ReturnedType returnedType) { return type.isInterface() ? Tuple.class : null; } - return introspectedQuery.get().hasConstructorExpression() // + return entityQuery.get().hasConstructorExpression() // ? null // : super.getTypeToRead(returnedType); } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NativeJpaQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NativeJpaQuery.java index 6fdeae05d9..1b107ebd25 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NativeJpaQuery.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NativeJpaQuery.java @@ -24,11 +24,8 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.repository.NativeQuery; -import org.springframework.data.repository.query.Parameters; -import org.springframework.data.jpa.repository.QueryRewriter; import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.data.repository.query.ReturnedType; -import org.springframework.data.repository.query.ValueExpressionDelegate; import org.springframework.lang.Nullable; import org.springframework.util.ObjectUtils; @@ -57,12 +54,11 @@ class NativeJpaQuery extends AbstractStringBasedJpaQuery { * @param queryString must not be {@literal null} or empty. * @param countQueryString must not be {@literal null} or empty. * @param queryConfiguration must not be {@literal null}. - * @param valueExpressionDelegate must not be {@literal null}. */ public NativeJpaQuery(JpaQueryMethod method, EntityManager em, String queryString, @Nullable String countQueryString, - QueryRewriter rewriter, JpaQueryConfiguration queryConfiguration) { + JpaQueryConfiguration queryConfiguration) { - super(method, em, queryString, countQueryString, rewriter, valueExpressionDelegate); + super(method, em, queryString, countQueryString, queryConfiguration); MergedAnnotations annotations = MergedAnnotations.from(method.getMethod()); MergedAnnotation annotation = annotations.get(NativeQuery.class); diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinderFactory.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinderFactory.java index 06ba90e3d5..c547a0ba00 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinderFactory.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinderFactory.java @@ -99,8 +99,10 @@ static ParameterBinder createQueryAwareBinder(JpaParameters parameters, Introspe QueryParameterSetterFactory basicSetterFactory = QueryParameterSetterFactory.basic(parameters); + boolean usesPaging = query instanceof EntityQuery eq && eq.usesPaging(); + return new ParameterBinder(parameters, createSetters(bindings, query, expressionSetterFactory, basicSetterFactory), - !query.usesPaging()); + !usesPaging); } private static List getBindings(JpaParameters parameters) { 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 55c168a4f5..e1e968c380 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 @@ -64,7 +64,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 index 8b2a3ac669..b88a6953f0 100644 --- 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 @@ -49,6 +49,7 @@ public class QueryEnhancerFactories { } enum BuiltinQueryEnhancerFactories implements QueryEnhancerFactory { + FALLBACK { @Override public boolean supports(DeclaredQuery query) { @@ -60,6 +61,7 @@ public QueryEnhancer create(DeclaredQuery query) { return new DefaultQueryEnhancer(query); } }, + JSQLPARSER { @Override public boolean supports(DeclaredQuery query) { @@ -75,6 +77,7 @@ public QueryEnhancer create(DeclaredQuery query) { throw new IllegalStateException("JSQLParser is not available on the class path"); } }, + HQL { @Override public boolean supports(DeclaredQuery query) { 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 9e0871c839..19be0faab9 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,14 +15,6 @@ */ 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 IntrospectedQuery}. * @@ -30,7 +22,7 @@ * @author Greg Turnquist * @author Mark Paluch * @author Christoph Strobl - * @since 2.7.0 + * @since 2.7 */ public interface QueryEnhancerFactory { @@ -51,84 +43,13 @@ public interface QueryEnhancerFactory { QueryEnhancer create(DeclaredQuery query); /** - * Creates a new {@link QueryEnhancer} for the given {@link IntrospectedQuery}. + * Creates a new {@link QueryEnhancerFactory} for the given {@link DeclaredQuery}. * * @param query must not be {@literal null}. * @return an implementation of {@link QueryEnhancer} that suits the query the most */ - static QueryEnhancer forQuery(DeclaredQuery query) { + static QueryEnhancerFactory forQuery(DeclaredQuery query) { return QueryEnhancerSelector.DEFAULT_SELECTOR.select(query); } - /** - * Get the native query enhancer for the given {@link DeclaredQuery query} based on {@link #NATIVE_QUERY_ENHANCER}. - * - * @param query the declared query. - * @return new instance of {@link QueryEnhancer}. - */ - private static QueryEnhancer getNativeQueryEnhancer(DeclaredQuery query) { - - if (NATIVE_QUERY_ENHANCER.equals(NativeQueryEnhancer.JSQLPARSER)) { - return new JSqlParserQueryEnhancer(query); - } - - return new DefaultQueryEnhancer(query); - } - - /** - * Possible choices for the {@link #NATIVE_PARSER_PROPERTY}. Resolve the parser through {@link #select()}. - * - * @since 3.3.5 - */ - 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; - } - } - } 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 index 2830c31fd4..75bee83f1d 100644 --- 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 @@ -38,7 +38,7 @@ public interface QueryEnhancerSelector { * @param query * @return */ - QueryEnhancer select(DeclaredQuery query); + QueryEnhancerFactory select(DeclaredQuery query); /** * Default {@link QueryEnhancerSelector} implementation using class-path information to determine enhancer @@ -85,11 +85,7 @@ public static QueryEnhancerFactory jpql() { } @Override - public QueryEnhancer select(DeclaredQuery query) { - return selectFactory(query).create(query); - } - - private QueryEnhancerFactory selectFactory(DeclaredQuery query) { + 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/SimpleJpaQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java index b1213955ae..1089c0e341 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; /** @@ -35,34 +33,19 @@ */ 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); - } - /** * 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 32e4d5be46..ad077da3ec 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,15 +58,15 @@ * @author Greg Turnquist * @author Yuriy Tsarkov */ -class StringQuery implements IntrospectedQuery { +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 QueryEnhancerSelector selector; private final boolean hasNamedParameters; /** @@ -77,6 +78,38 @@ 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 = factory.create(this); + + boolean hasNamedParameters = false; + for (ParameterBinding parameterBinding : getParameterBindings()) { + if (parameterBinding.getIdentifier().hasName() && parameterBinding.getOrigin().isMethodArgument()) { + hasNamedParameters = true; + break; + } + } + + this.hasNamedParameters = hasNamedParameters; + } + /** * Creates a new {@link StringQuery} from the given JPQL query. * @@ -95,8 +128,8 @@ public StringQuery(String query, boolean isNative) { this.bindings, queryMeta); this.usesJdbcStyleParameters = queryMeta.usesJdbcStyleParameters; - this.queryEnhancer = selector.select(this); - this.selector = selector; + this.queryEnhancerFactory = selector.select(this); + this.queryEnhancer = queryEnhancerFactory.create(this); boolean hasNamedParameters = false; for (ParameterBinding parameterBinding : getParameterBindings()) { @@ -129,7 +162,7 @@ public List getParameterBindings() { public IntrospectedQuery deriveCountQuery(@Nullable String countQueryProjection) { StringQuery stringQuery = new StringQuery(this.queryEnhancer.createCountQueryFor(countQueryProjection), // - this.isNative, this.selector); + this.isNative, this.queryEnhancerFactory); if (this.hasParameterBindings() && !this.getParameterBindings().equals(stringQuery.getParameterBindings())) { stringQuery.getParameterBindings().clear(); @@ -139,6 +172,11 @@ public IntrospectedQuery deriveCountQuery(@Nullable String countQueryProjection) return stringQuery; } + @Override + public String applySorting(Sort sort) { + return queryEnhancer.applySorting(sort); + } + @Override public boolean usesJdbcStyleParameters() { return usesJdbcStyleParameters; @@ -149,7 +187,6 @@ public String getQueryString() { return query; } - @Override @Nullable public String getAlias() { return queryEnhancer.detectAlias(); @@ -254,8 +291,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); @@ -361,8 +397,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 76212b19f7..ceac6bfd3c 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,7 +34,6 @@ 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.*; import org.springframework.data.jpa.util.JpaMetamodel; @@ -53,7 +52,6 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key; import org.springframework.data.repository.query.ReturnedType; import org.springframework.data.repository.query.ValueExpressionDelegate; -import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; @@ -74,10 +72,7 @@ */ public class JpaRepositoryFactory extends RepositoryFactorySupport { - private static final SpelExpressionParser PARSER = new SpelExpressionParser(); - private final EntityManager entityManager; - private final QueryExtractor extractor; private final CrudMethodMetadataPostProcessor crudMethodMetadataPostProcessor; private final CrudMethodMetadata crudMethodMetadata; @@ -97,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); @@ -247,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/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 daf4da9737..bfcf855b2c 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 @@ -53,8 +53,7 @@ class AbstractStringBasedJpaQueryIntegrationTests { private static final JpaQueryConfiguration CONFIG = new JpaQueryConfiguration(QueryRewriterProvider.simple(), - QueryEnhancerSelector.DEFAULT_SELECTOR, QueryMethodEvaluationContextProvider.DEFAULT, EscapeCharacter.DEFAULT, - new SpelExpressionParser()); + QueryEnhancerSelector.DEFAULT_SELECTOR, ValueExpressionDelegate.create(), EscapeCharacter.DEFAULT); @PersistenceContext EntityManager em; @@ -69,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, CONFIG, - 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 8fe034babc..d1e6a5e433 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 @@ -55,8 +55,7 @@ class AbstractStringBasedJpaQueryUnitTests { private static final JpaQueryConfiguration CONFIG = new JpaQueryConfiguration(QueryRewriterProvider.simple(), - QueryEnhancerSelector.DEFAULT_SELECTOR, QueryMethodEvaluationContextProvider.DEFAULT, EscapeCharacter.DEFAULT, - new SpelExpressionParser()); + QueryEnhancerSelector.DEFAULT_SELECTOR, ValueExpressionDelegate.create(), EscapeCharacter.DEFAULT); @Test // GH-3310 void shouldNotAttemptToAppendSortIfNoSortArgumentPresent() { @@ -129,7 +128,7 @@ static class InvocationCapturingStringQueryStub extends AbstractStringBasedJpaQu private final MultiValueMap capturedArguments = new LinkedMultiValueMap<>(3); InvocationCapturingStringQueryStub(Method targetMethod, JpaQueryMethod queryMethod, String queryString, - @Nullable String countQueryString, JpaQueryConfiguration queryContext) { + @Nullable String countQueryString, JpaQueryConfiguration queryConfiguration) { super(queryMethod, new Supplier() { @Override @@ -143,7 +142,7 @@ public EntityManager get() { return em; } - }.get(), queryString, countQueryString, queryContext, 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 69dd488c8d..920cebe45c 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 @@ -18,7 +18,7 @@ import static org.assertj.core.api.Assertions.*; import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.api.Test; import org.springframework.data.domain.Sort; @@ -35,14 +35,14 @@ QueryEnhancer createQueryEnhancer(DeclaredQuery query) { } @Override - @ParameterizedTest // GH-2511, GH-2773 + @Test // GH-2511, GH-2773 @Disabled("Not properly supported by QueryUtils") 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/ExpressionBasedStringQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java index 58bda27419..fac56ee960 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,10 +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.QueryMethodEvaluationContextProvider; +import org.springframework.data.repository.query.ValueExpressionDelegate; import org.springframework.data.repository.query.parser.Part.Type; /** @@ -50,8 +48,7 @@ class ExpressionBasedStringQueryUnitTests { private static final JpaQueryConfiguration CONFIG = new JpaQueryConfiguration(QueryRewriterProvider.simple(), - QueryEnhancerSelector.DEFAULT_SELECTOR, QueryMethodEvaluationContextProvider.DEFAULT, EscapeCharacter.DEFAULT, - ValueExpressionParser.create()); + QueryEnhancerSelector.DEFAULT_SELECTOR, ValueExpressionDelegate.create(), EscapeCharacter.DEFAULT); @Mock JpaEntityMetadata metadata; @@ -64,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"); } @@ -84,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); } @@ -97,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); } @@ -110,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(); } @@ -118,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(); } @@ -126,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(); } @@ -135,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( @@ -160,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()) @@ -185,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"); } @@ -194,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"); } @@ -203,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/JSqlParserQueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerUnitTests.java index 54d8a57fb0..37534c998b 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 @@ -44,7 +44,7 @@ QueryEnhancer createQueryEnhancer(DeclaredQuery 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 cff7fc83c6..9a4de92f68 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 @@ -33,7 +33,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; -import org.springframework.beans.factory.BeanFactory; + import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -47,8 +47,8 @@ import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; import org.springframework.data.repository.query.QueryLookupStrategy; import org.springframework.data.repository.query.QueryLookupStrategy.Key; -import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; import org.springframework.data.repository.query.RepositoryQuery; +import org.springframework.data.repository.query.ValueExpressionDelegate; /** * Unit tests for {@link JpaQueryLookupStrategy}. @@ -63,7 +63,8 @@ @MockitoSettings(strictness = Strictness.LENIENT) class JpaQueryLookupStrategyUnitTests { - private static final QueryMethodEvaluationContextProvider EVALUATION_CONTEXT_PROVIDER = QueryMethodEvaluationContextProvider.DEFAULT; + private static final JpaQueryConfiguration CONFIG = new JpaQueryConfiguration(QueryRewriterProvider.simple(), + QueryEnhancerSelector.DEFAULT_SELECTOR, ValueExpressionDelegate.create(), EscapeCharacter.DEFAULT); @Mock EntityManager em; @Mock EntityManagerFactory emf; @@ -71,7 +72,6 @@ class JpaQueryLookupStrategyUnitTests { @Mock NamedQueries namedQueries; @Mock Metamodel metamodel; @Mock ProjectionFactory projectionFactory; - @Mock BeanFactory beanFactory; private JpaQueryMethodFactory queryMethodFactory; @@ -89,7 +89,7 @@ void setUp() { void invalidAnnotatedQueryCausesException() throws Exception { QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND, - EVALUATION_CONTEXT_PROVIDER, new BeanFactoryQueryRewriterProvider(beanFactory), EscapeCharacter.DEFAULT); + CONFIG); Method method = UserRepository.class.getMethod("findByFoo", String.class); RepositoryMetadata metadata = new DefaultRepositoryMetadata(UserRepository.class); @@ -101,7 +101,7 @@ void invalidAnnotatedQueryCausesException() throws Exception { void considersNamedCountQuery() throws Exception { QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND, - EVALUATION_CONTEXT_PROVIDER, 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"); @@ -123,7 +123,7 @@ void considersNamedCountQuery() throws Exception { void considersNamedCountOnStringQueryQuery() throws Exception { QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND, - EVALUATION_CONTEXT_PROVIDER, 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"); @@ -142,7 +142,7 @@ void considersNamedCountOnStringQueryQuery() throws Exception { void prefersDeclaredQuery() throws Exception { QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND, - EVALUATION_CONTEXT_PROVIDER, new BeanFactoryQueryRewriterProvider(beanFactory), EscapeCharacter.DEFAULT); + CONFIG); Method method = UserRepository.class.getMethod("annotatedQueryWithQueryAndQueryName"); RepositoryMetadata metadata = new DefaultRepositoryMetadata(UserRepository.class); @@ -155,7 +155,7 @@ void prefersDeclaredQuery() throws Exception { void namedQueryWithSortShouldThrowIllegalStateException() throws NoSuchMethodException { QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND, - EVALUATION_CONTEXT_PROVIDER, new BeanFactoryQueryRewriterProvider(beanFactory), EscapeCharacter.DEFAULT); + CONFIG); Method method = UserRepository.class.getMethod("customNamedQuery", String.class, Sort.class); RepositoryMetadata metadata = new DefaultRepositoryMetadata(UserRepository.class); @@ -180,7 +180,7 @@ void noQueryShouldNotBeInvoked() { void customQueryWithQuestionMarksShouldWork() throws NoSuchMethodException { QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, queryMethodFactory, Key.CREATE_IF_NOT_FOUND, - EVALUATION_CONTEXT_PROVIDER, 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/NativeJpaQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NativeJpaQueryUnitTests.java index 7a9cf35d1f..c03c188e1f 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; @@ -82,7 +81,8 @@ private NativeJpaQuery getQuery(Class repository, String method, Class... 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)); return query; } 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 30645398b2..66547d228f 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 1c63416dd0..f833f60685 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,7 +35,7 @@ abstract class QueryEnhancerTckTests { @MethodSource("nativeCountQueries") // GH-2773 void shouldDeriveNativeCountQuery(String query, String expected) { - QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.nativeQuery(query)); + QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.ofNative(query)); String countQueryFor = enhancer.createCountQueryFor(); // lenient cleanup to allow for rendering variance @@ -115,7 +115,7 @@ static Stream nativeCountQueries() { @MethodSource("jpqlCountQueries") void shouldDeriveJpqlCountQuery(String query, String expected) { - QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.jpql(query)); + QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.ofJpql(query)); String countQueryFor = enhancer.createCountQueryFor(null); assertThat(countQueryFor).isEqualToIgnoringCase(expected); @@ -174,7 +174,7 @@ static Stream jpqlCountQueries() { @MethodSource("nativeQueriesWithVariables") void shouldDeriveNativeCountQueryWithVariable(String query, String expected) { - QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.nativeQuery(query)); + QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.ofNative(query)); String countQueryFor = enhancer.createCountQueryFor(); assertThat(countQueryFor).isEqualToIgnoringCase(expected); 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 0d580db52c..e2d3e8cf78 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 @@ -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 @@ -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(); @@ -697,7 +697,7 @@ private static void assertCountQuery(StringQuery originalQuery, String countQuer } private static QueryEnhancer getEnhancer(IntrospectedQuery query) { - return QueryEnhancerFactory.forQuery(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 9b363e3c7b..05ae79c0f0 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 @@ -53,7 +53,8 @@ void before() { @Test // DATAJPA-1058 void noExceptionWhenQueryDoesNotContainNamedParameters() { - setterFactory.create(binding, IntrospectedQuery.of("from Employee e", false)); + setterFactory.create(binding, + EntityQuery.introspectJpql("from Employee e", QueryEnhancerSelector.DEFAULT_SELECTOR)); } @Test // DATAJPA-1058 @@ -63,7 +64,8 @@ void exceptionWhenQueryContainNamedParametersAndMethodParametersAreNotNamed() { assertThatExceptionOfType(IllegalStateException.class) // .isThrownBy(() -> setterFactory.create(binding, - IntrospectedQuery.of("from Employee e where e.name = :NamedParameter", false))) // + EntityQuery.introspectJpql("from Employee e where e.name = :NamedParameter", + QueryEnhancerSelector.DEFAULT_SELECTOR))) // .withMessageContaining("Java 8") // .withMessageContaining("@Param") // .withMessageContaining("-parameters"); @@ -82,7 +84,8 @@ void exceptionWhenCriteriaQueryContainsInsufficientAmountOfParameters() { assertThatExceptionOfType(IllegalArgumentException.class) // .isThrownBy(() -> setterFactory.create(binding, - IntrospectedQuery.of("from Employee e where e.name = :NamedParameter", false))) // + EntityQuery.introspectJpql("from Employee e where e.name = :NamedParameter", + QueryEnhancerSelector.DEFAULT_SELECTOR))) // .withMessage("At least 1 parameter(s) provided but only 0 parameter(s) present in query"); } @@ -98,7 +101,9 @@ void exceptionWhenBasicQueryContainsInsufficientAmountOfParameters() { assertThatExceptionOfType(IllegalArgumentException.class) // .isThrownBy( - () -> setterFactory.create(binding, IntrospectedQuery.of("from Employee e where e.name = ?1", false))) // + () -> 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 fa36acad2e..2cad1b6ddb 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.query.JpaQueryLookupStrategy.DeclaredQueryLookupStrategy; import org.springframework.data.jpa.repository.sample.UserRepository; import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.projection.SpelAwareProxyProjectionFactory; @@ -76,8 +75,7 @@ class SimpleJpaQueryUnitTests { private static final JpaQueryConfiguration CONFIG = new JpaQueryConfiguration(QueryRewriterProvider.simple(), - QueryEnhancerSelector.DEFAULT_SELECTOR, QueryMethodEvaluationContextProvider.DEFAULT, EscapeCharacter.DEFAULT, - new SpelExpressionParser()); + QueryEnhancerSelector.DEFAULT_SELECTOR, ValueExpressionDelegate.create(), EscapeCharacter.DEFAULT); private static final String USER_QUERY = "select u from User u"; @@ -123,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); @@ -138,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) })); @@ -153,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); @@ -173,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); @@ -243,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)); @@ -287,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, - EVALUATION_CONTEXT_PROVIDER, PARSER); + "select count(u.id) from #{#entityName} u", CONFIG); jpaQuery.createCountQuery( new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[] { PageRequest.of(1, 10) })); @@ -303,8 +297,8 @@ private AbstractJpaQuery createJpaQuery(Method method) { 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) { 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 328dc3ab59..34814f1fc9 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,7 +715,9 @@ void usingGreaterThanWithNamedParameter() { void checkNumberOfNamedParameters(String query, int expectedSize, String label, boolean nativeQuery) { - IntrospectedQuery introspectedQuery = IntrospectedQuery.of(query, nativeQuery); + EntityQuery introspectedQuery = nativeQuery + ? EntityQuery.introspectNativeQuery(query, QueryEnhancerSelector.DEFAULT_SELECTOR) + : EntityQuery.introspectJpql(query, QueryEnhancerSelector.DEFAULT_SELECTOR); assertThat(introspectedQuery.hasNamedParameter()) // .describedAs("hasNamed Parameter " + label) //