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