DATAJPA-628 - Use a shared SpelParser instead of recreating it.
We now use a shared SpelExpressionParser and propagate this through the String-based JpaRepositoryQuery implementations to avoid reinstantiations. Cleaned up ParameterBinder inheritance hierarchy by merging (and removing) ExpressionAwareParameterBinder into SpelExpressionStringQueryParameterBinder. Original pull request: #121.
This commit is contained in:
committed by
Oliver Gierke
parent
5c906ce73c
commit
0184c95a4b
@@ -22,6 +22,7 @@ import javax.persistence.TypedQuery;
|
||||
import org.springframework.data.repository.query.EvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.ParameterAccessor;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -35,6 +36,7 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
|
||||
private final StringQuery query;
|
||||
private final StringQuery countQuery;
|
||||
private final EvaluationContextProvider evaluationContextProvider;
|
||||
private final SpelExpressionParser parser;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AbstractStringBasedJpaQuery} from the given {@link JpaQueryMethod}, {@link EntityManager} and
|
||||
@@ -44,19 +46,22 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
|
||||
* @param em must not be {@literal null}.
|
||||
* @param queryString must not be {@literal null}.
|
||||
* @param evaluationContextProvider must not be {@literal null}.
|
||||
* @param parser must not be {@literal null}.
|
||||
*/
|
||||
public AbstractStringBasedJpaQuery(JpaQueryMethod method, EntityManager em, String queryString,
|
||||
EvaluationContextProvider evaluationContextProvider) {
|
||||
EvaluationContextProvider 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 or empty!");
|
||||
|
||||
this.evaluationContextProvider = evaluationContextProvider;
|
||||
this.query = new ExpressionBasedStringQuery(queryString, method.getEntityInformation());
|
||||
this.query = new ExpressionBasedStringQuery(queryString, method.getEntityInformation(), parser);
|
||||
this.countQuery = new StringQuery(method.getCountQuery() != null ? method.getCountQuery()
|
||||
: QueryUtils.createCountQueryFor(this.query.getQueryString(), method.getCountQueryProjection()));
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -81,7 +86,7 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
|
||||
@Override
|
||||
protected ParameterBinder createBinder(Object[] values) {
|
||||
return new SpelExpressionStringQueryParameterBinder(getQueryMethod().getParameters(), values, query,
|
||||
evaluationContextProvider);
|
||||
evaluationContextProvider, parser);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 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
|
||||
*
|
||||
* http://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.repository.query.EvaluationContextProvider;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link ParameterBinder} that is able to detect and dynamically evaluate SpEL expression based parameters.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
class ExpressionAwareParameterBinder extends ParameterBinder {
|
||||
|
||||
private final EvaluationContextProvider evaluationContextProvider;
|
||||
|
||||
/**
|
||||
* Creates a new {@literal ExpressionAwareParameterBinder}.
|
||||
*
|
||||
* @param parameters
|
||||
* @param evaluationContextProvider must not be {@literal null}.
|
||||
*/
|
||||
public ExpressionAwareParameterBinder(JpaParameters parameters, EvaluationContextProvider evaluationContextProvider) {
|
||||
this(parameters, new Object[0], evaluationContextProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@literal ExpressionAwareParameterBinder}.
|
||||
*
|
||||
* @param parameters
|
||||
* @param values
|
||||
* @param evaluationContextProvider must not be {@literal null}.
|
||||
*/
|
||||
public ExpressionAwareParameterBinder(JpaParameters parameters, Object[] values,
|
||||
EvaluationContextProvider evaluationContextProvider) {
|
||||
|
||||
super(parameters, values);
|
||||
|
||||
Assert.notNull(evaluationContextProvider, "EvaluationContextProvider must not be null!");
|
||||
|
||||
this.evaluationContextProvider = evaluationContextProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given {@code expressionString} into a SpEL {@link Expression}.
|
||||
*
|
||||
* @param expressionString
|
||||
* @return
|
||||
*/
|
||||
protected Expression parseExpressionString(String expressionString) {
|
||||
return new SpelExpressionParser().parseExpression(expressionString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the given {@code expressionString} as a SpEL {@link Expression}.
|
||||
*
|
||||
* @param expressionString
|
||||
* @return
|
||||
*/
|
||||
protected Object evaluateExpression(String expressionString) {
|
||||
return evaluateExpression(parseExpressionString(expressionString));
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the given SpEL {@link Expression}.
|
||||
*
|
||||
* @param expr
|
||||
* @return
|
||||
*/
|
||||
protected Object evaluateExpression(Expression expr) {
|
||||
return expr.getValue(getEvaluationContext(), Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link StandardEvaluationContext} to use for evaluation.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected EvaluationContext getEvaluationContext() {
|
||||
return evaluationContextProvider.getEvaluationContext(getParameters(), getValues());
|
||||
}
|
||||
}
|
||||
@@ -36,26 +36,32 @@ import org.springframework.util.Assert;
|
||||
class ExpressionBasedStringQuery extends StringQuery {
|
||||
|
||||
private static final String ENTITY_NAME = "entityName";
|
||||
private static final String ENTITY_NAME_VARIABLE = "#" + ENTITY_NAME;
|
||||
private static final String ENTITY_NAME_VARIABLE_EXPRESSION = "#{" + ENTITY_NAME_VARIABLE + "}";
|
||||
|
||||
/**
|
||||
* Creates a new {@link ExpressionBasedStringQuery} for the given query and {@link EntityMetadata}.
|
||||
*
|
||||
* @param query must not be {@literal null} or empty.
|
||||
* @param metadata must not be {@literal null}.
|
||||
* @param parser must not be {@literal null}.
|
||||
*/
|
||||
public ExpressionBasedStringQuery(String query, JpaEntityMetadata<?> metadata) {
|
||||
super(renderQueryIfExpressionOrReturnQuery(query, metadata));
|
||||
public ExpressionBasedStringQuery(String query, JpaEntityMetadata<?> metadata, SpelExpressionParser parser) {
|
||||
super(renderQueryIfExpressionOrReturnQuery(query, metadata, parser));
|
||||
}
|
||||
|
||||
/**
|
||||
* @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}.
|
||||
* @param parser Must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private static String renderQueryIfExpressionOrReturnQuery(String query, JpaEntityMetadata<?> metadata) {
|
||||
private static String renderQueryIfExpressionOrReturnQuery(String query, JpaEntityMetadata<?> metadata,
|
||||
SpelExpressionParser parser) {
|
||||
|
||||
Assert.notNull(query, "query must not be null!");
|
||||
Assert.notNull(metadata, "metadata must not be null!");
|
||||
Assert.notNull(parser, "parser must not be null!");
|
||||
|
||||
if (!containsExpression(query)) {
|
||||
return query;
|
||||
@@ -64,7 +70,6 @@ class ExpressionBasedStringQuery extends StringQuery {
|
||||
StandardEvaluationContext evalContext = new StandardEvaluationContext();
|
||||
evalContext.setVariable(ENTITY_NAME, metadata.getEntityName());
|
||||
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
Expression expr = parser.parseExpression(query, ParserContext.TEMPLATE_EXPRESSION);
|
||||
|
||||
Object result = expr.getValue(evalContext, String.class);
|
||||
@@ -72,6 +77,6 @@ class ExpressionBasedStringQuery extends StringQuery {
|
||||
}
|
||||
|
||||
private static boolean containsExpression(String query) {
|
||||
return query.contains("#{#" + ENTITY_NAME + "}");
|
||||
return query.contains(ENTITY_NAME_VARIABLE_EXPRESSION);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.EvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
||||
/**
|
||||
* Factory to create the appropriate {@link RepositoryQuery} for a {@link JpaQueryMethod}.
|
||||
@@ -33,6 +34,11 @@ enum JpaQueryFactory {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/**
|
||||
* The {@link SpelExpressionParser} is shared between all created {@link RepositoryQuery}s.
|
||||
*/
|
||||
private final SpelExpressionParser PARSER = new SpelExpressionParser();
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JpaQueryFactory.class);
|
||||
|
||||
/**
|
||||
@@ -67,8 +73,8 @@ enum JpaQueryFactory {
|
||||
return null;
|
||||
}
|
||||
|
||||
return method.isNativeQuery() ? new NativeJpaQuery(method, em, queryString, evaluationContextProvider) : //
|
||||
new SimpleJpaQuery(method, em, queryString, evaluationContextProvider);
|
||||
return method.isNativeQuery() ? new NativeJpaQuery(method, em, queryString, evaluationContextProvider, PARSER) : //
|
||||
new SimpleJpaQuery(method, em, queryString, evaluationContextProvider, PARSER);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,6 +21,7 @@ import javax.persistence.Query;
|
||||
import org.springframework.data.repository.query.EvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.Parameters;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
||||
/**
|
||||
* {@link RepositoryQuery} implementation that inspects a {@link org.springframework.data.repository.query.QueryMethod}
|
||||
@@ -40,9 +41,9 @@ final class NativeJpaQuery extends AbstractStringBasedJpaQuery {
|
||||
* @param evaluationContextProvider
|
||||
*/
|
||||
public NativeJpaQuery(JpaQueryMethod method, EntityManager em, String queryString,
|
||||
EvaluationContextProvider evaluationContextProvider) {
|
||||
EvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) {
|
||||
|
||||
super(method, em, queryString, evaluationContextProvider);
|
||||
super(method, em, queryString, evaluationContextProvider, parser);
|
||||
|
||||
Parameters<?, ?> parameters = method.getParameters();
|
||||
boolean hasPagingOrSortingParameter = parameters.hasPageableParameter() || parameters.hasSortParameter();
|
||||
|
||||
@@ -20,6 +20,7 @@ import javax.persistence.Query;
|
||||
|
||||
import org.springframework.data.repository.query.EvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
||||
/**
|
||||
* {@link RepositoryQuery} implementation that inspects a {@link org.springframework.data.repository.query.QueryMethod}
|
||||
@@ -33,26 +34,30 @@ final class SimpleJpaQuery extends AbstractStringBasedJpaQuery {
|
||||
|
||||
/**
|
||||
* Creates a new {@link SimpleJpaQuery} encapsulating the query annotated on the given {@link JpaQueryMethod}.
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @param em must not be {@literal null}.
|
||||
*
|
||||
* @param method must not be {@literal null}
|
||||
* @param em 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,
|
||||
EvaluationContextProvider evaluationContextProvider) {
|
||||
this(method, em, method.getAnnotatedQuery(), evaluationContextProvider);
|
||||
public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, EvaluationContextProvider evaluationContextProvider,
|
||||
SpelExpressionParser parser) {
|
||||
this(method, em, method.getAnnotatedQuery(), evaluationContextProvider, parser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 method must not be {@literal null}
|
||||
* @param em must not be {@literal null}
|
||||
* @param queryString must not be {@literal null} or empty
|
||||
* @param evaluationContextProvider must not be {@literal null}
|
||||
* @param parser must not be {@literal null}
|
||||
*/
|
||||
public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, String queryString,
|
||||
EvaluationContextProvider evaluationContextProvider) {
|
||||
EvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) {
|
||||
|
||||
super(method, em, queryString, evaluationContextProvider);
|
||||
super(method, em, queryString, evaluationContextProvider, parser);
|
||||
|
||||
validateQuery(getQuery().getQueryString(), String.format("Validation failed for query for method %s!", method));
|
||||
|
||||
|
||||
@@ -15,11 +15,17 @@
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Query;
|
||||
|
||||
import org.springframework.data.jpa.repository.query.JpaParameters.JpaParameter;
|
||||
import org.springframework.data.jpa.repository.query.StringQuery.ParameterBinding;
|
||||
import org.springframework.data.repository.query.EvaluationContextProvider;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -30,6 +36,8 @@ import org.springframework.util.Assert;
|
||||
class SpelExpressionStringQueryParameterBinder extends StringQueryParameterBinder {
|
||||
|
||||
private final StringQuery query;
|
||||
private final EvaluationContextProvider evaluationContextProvider;
|
||||
private final SpelExpressionParser parser;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SpelExpressionStringQueryParameterBinder}.
|
||||
@@ -38,18 +46,22 @@ class SpelExpressionStringQueryParameterBinder extends StringQueryParameterBinde
|
||||
* @param values must not be {@literal null}
|
||||
* @param query must not be {@literal null}
|
||||
* @param evaluationContextProvider must not be {@literal null}
|
||||
* @param parser must not be {@literal null}
|
||||
*/
|
||||
public SpelExpressionStringQueryParameterBinder(JpaParameters parameters, Object[] values, StringQuery query,
|
||||
EvaluationContextProvider evaluationContextProvider) {
|
||||
|
||||
super(parameters, values, query, evaluationContextProvider);
|
||||
EvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) {
|
||||
|
||||
super(parameters, values, query);
|
||||
Assert.notNull(evaluationContextProvider, "EvaluationContextProvider must not be null!");
|
||||
Assert.notNull(parser, "SpelExpressionParser must not be null!");
|
||||
|
||||
this.evaluationContextProvider = evaluationContextProvider;
|
||||
this.query = query;
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.query.ParameterBinder#bind(javax.persistence.Query)
|
||||
*/
|
||||
@Override
|
||||
@@ -83,11 +95,9 @@ class SpelExpressionStringQueryParameterBinder extends StringQueryParameterBinde
|
||||
jpaQuery.setParameter(binding.getPosition(), binding.prepare(value));
|
||||
}
|
||||
} catch (IllegalArgumentException iae) {
|
||||
/*
|
||||
* Since Eclipse doesn't reliably report whether a query has parameters
|
||||
* we simply try to set the parameters and ignore possible failures.
|
||||
*
|
||||
*/
|
||||
|
||||
// Since Eclipse doesn't reliably report whether a query has parameters
|
||||
// we simply try to set the parameters and ignore possible failures.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,4 +110,62 @@ class SpelExpressionStringQueryParameterBinder extends StringQueryParameterBinde
|
||||
String className = jpaQuery.getClass().getName();
|
||||
return className.startsWith("org.apache.openjpa") || className.startsWith("org.hibernate");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given {@code expressionString} into a SpEL {@link Expression}.
|
||||
*
|
||||
* @param expressionString
|
||||
* @return
|
||||
*/
|
||||
private Expression parseExpressionString(String expressionString) {
|
||||
return parser.parseExpression(expressionString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the given SpEL {@link Expression}.
|
||||
*
|
||||
* @param expr
|
||||
* @return
|
||||
*/
|
||||
private Object evaluateExpression(Expression expr) {
|
||||
return expr.getValue(getEvaluationContext(), Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link StandardEvaluationContext} to use for evaluation.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private EvaluationContext getEvaluationContext() {
|
||||
return evaluationContextProvider.getEvaluationContext(getParameters(), getValues());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.query.ParameterBinder#canBindParameter(org.springframework.data.jpa.repository.query.JpaParameters.JpaParameter)
|
||||
*/
|
||||
@Override
|
||||
protected boolean canBindParameter(JpaParameter parameter) {
|
||||
|
||||
List<ParameterBinding> parameterBindings = query.getParameterBindings();
|
||||
|
||||
// if no parameter bindings are present, we simply rely on the check in super.
|
||||
if (parameterBindings.isEmpty()) {
|
||||
return super.canBindParameter(parameter);
|
||||
}
|
||||
|
||||
// otherwise determine whether there are any non expression parameters left to be bound.
|
||||
int expressionParameterCount = 0;
|
||||
for (ParameterBinding binding : parameterBindings) {
|
||||
|
||||
if (binding.isExpression()) {
|
||||
expressionParameterCount++;
|
||||
}
|
||||
}
|
||||
|
||||
boolean allParametersAreUsedInExpressions = parameterBindings.size() - expressionParameterCount == 0;
|
||||
|
||||
// if all parameters are used in expressions, then we can skip their bindings now, since they'll get bound later.
|
||||
return !allParametersAreUsedInExpressions && super.canBindParameter(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Query;
|
||||
|
||||
import org.springframework.data.jpa.repository.query.JpaParameters.JpaParameter;
|
||||
import org.springframework.data.jpa.repository.query.StringQuery.LikeParameterBinding;
|
||||
import org.springframework.data.jpa.repository.query.StringQuery.ParameterBinding;
|
||||
import org.springframework.data.repository.query.EvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.Parameter;
|
||||
import org.springframework.data.repository.query.Parameters;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -33,7 +30,7 @@ import org.springframework.util.Assert;
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public class StringQueryParameterBinder extends ExpressionAwareParameterBinder {
|
||||
public class StringQueryParameterBinder extends ParameterBinder {
|
||||
|
||||
private final StringQuery query;
|
||||
|
||||
@@ -44,12 +41,10 @@ public class StringQueryParameterBinder extends ExpressionAwareParameterBinder {
|
||||
* @param parameters must not be {@literal null}.
|
||||
* @param values must not be {@literal null}.
|
||||
* @param query must not be {@literal null}.
|
||||
* @param evaluationContextProvider must not be {@literal null}.
|
||||
*/
|
||||
public StringQueryParameterBinder(JpaParameters parameters, Object[] values, StringQuery query,
|
||||
EvaluationContextProvider evaluationContextProvider) {
|
||||
public StringQueryParameterBinder(JpaParameters parameters, Object[] values, StringQuery query) {
|
||||
|
||||
super(parameters, values, evaluationContextProvider);
|
||||
super(parameters, values);
|
||||
|
||||
Assert.notNull(query, "StringQuery must not be null!");
|
||||
this.query = query;
|
||||
@@ -66,34 +61,6 @@ public class StringQueryParameterBinder extends ExpressionAwareParameterBinder {
|
||||
super.bind(jpaQuery, methodParameter, binding.prepare(value), position);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.query.ParameterBinder#canBindParameter(org.springframework.data.jpa.repository.query.JpaParameters.JpaParameter)
|
||||
*/
|
||||
@Override
|
||||
protected boolean canBindParameter(JpaParameter parameter) {
|
||||
|
||||
List<ParameterBinding> parameterBindings = query.getParameterBindings();
|
||||
|
||||
// if no parameter bindings are present, we simply rely on the check in super.
|
||||
if (parameterBindings.isEmpty()) {
|
||||
return super.canBindParameter(parameter);
|
||||
}
|
||||
|
||||
// otherwise determine whether there are any non expression parameters left to be bound.
|
||||
int expressionParameterCount = 0;
|
||||
for (ParameterBinding binding : parameterBindings) {
|
||||
|
||||
if (binding.isExpression()) {
|
||||
expressionParameterCount++;
|
||||
}
|
||||
}
|
||||
|
||||
boolean allParametersAreUsedInExpressions = parameterBindings.size() - expressionParameterCount == 0;
|
||||
|
||||
// if all parameters are used in expressions, then we can skip their bindings now, since they'll get bound later.
|
||||
return !allParametersAreUsedInExpressions && super.canBindParameter(parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the {@link LikeParameterBinding} to be applied before binding a parameter value to the query.
|
||||
*
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ExpressionBasedStringQuery}.
|
||||
@@ -35,6 +36,8 @@ public class ExpressionBasedStringQueryUnitTests {
|
||||
|
||||
@Mock JpaEntityMetadata<?> metadata;
|
||||
|
||||
static final SpelExpressionParser SPEL_PARSER = new SpelExpressionParser();
|
||||
|
||||
/**
|
||||
* @see DATAJPA-170
|
||||
*/
|
||||
@@ -44,7 +47,7 @@ public class ExpressionBasedStringQueryUnitTests {
|
||||
when(metadata.getEntityName()).thenReturn("User");
|
||||
|
||||
String source = "select from #{#entityName} u where u.firstname like :firstname";
|
||||
StringQuery query = new ExpressionBasedStringQuery(source, metadata);
|
||||
StringQuery query = new ExpressionBasedStringQuery(source, metadata, SPEL_PARSER);
|
||||
assertThat(query.getQueryString(), is("select from User u where u.firstname like :firstname"));
|
||||
}
|
||||
|
||||
@@ -56,7 +59,7 @@ public class ExpressionBasedStringQueryUnitTests {
|
||||
|
||||
when(metadata.getEntityName()).thenReturn("User");
|
||||
|
||||
StringQuery query = new ExpressionBasedStringQuery("select u from #{#entityName} u", metadata);
|
||||
StringQuery query = new ExpressionBasedStringQuery("select u from #{#entityName} u", metadata, SPEL_PARSER);
|
||||
assertThat(query.getAlias(), is("u"));
|
||||
assertThat(query.getQueryString(), is("select u from User u"));
|
||||
}
|
||||
|
||||
@@ -41,8 +41,9 @@ import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.core.NamedQueries;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.data.repository.query.DefaultEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.EvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
|
||||
/**
|
||||
@@ -54,6 +55,7 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class JpaQueryLookupStrategyUnitTests {
|
||||
|
||||
private static final EvaluationContextProvider EVALUATION_CONTEXT_PROVIDER = DefaultEvaluationContextProvider.INSTANCE;
|
||||
@Mock EntityManager em;
|
||||
@Mock EntityManagerFactory emf;
|
||||
@Mock QueryExtractor extractor;
|
||||
@@ -75,7 +77,7 @@ public class JpaQueryLookupStrategyUnitTests {
|
||||
public void invalidAnnotatedQueryCausesException() throws Exception {
|
||||
|
||||
QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, Key.CREATE_IF_NOT_FOUND, extractor,
|
||||
DefaultEvaluationContextProvider.INSTANCE);
|
||||
EVALUATION_CONTEXT_PROVIDER);
|
||||
Method method = UserRepository.class.getMethod("findByFoo", String.class);
|
||||
RepositoryMetadata metadata = new DefaultRepositoryMetadata(UserRepository.class);
|
||||
|
||||
@@ -97,7 +99,7 @@ public class JpaQueryLookupStrategyUnitTests {
|
||||
public void sholdThrowMorePreciseExceptionIfTryingToUsePaginationInNativeQueries() throws Exception {
|
||||
|
||||
QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, Key.CREATE_IF_NOT_FOUND, extractor,
|
||||
DefaultEvaluationContextProvider.INSTANCE);
|
||||
EVALUATION_CONTEXT_PROVIDER);
|
||||
Method method = UserRepository.class.getMethod("findByInvalidNativeQuery", String.class, Pageable.class);
|
||||
RepositoryMetadata metadata = new DefaultRepositoryMetadata(UserRepository.class);
|
||||
|
||||
|
||||
@@ -44,8 +44,10 @@ import org.springframework.data.jpa.provider.QueryExtractor;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.jpa.repository.sample.UserRepository;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.data.repository.query.DefaultEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.EvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
||||
/**
|
||||
* Unit test for {@link SimpleJpaQuery}.
|
||||
@@ -57,6 +59,8 @@ import org.springframework.data.repository.query.DefaultEvaluationContextProvide
|
||||
public class SimpleJpaQueryUnitTests {
|
||||
|
||||
static final String USER_QUERY = "select u from User u";
|
||||
static final SpelExpressionParser PARSER = new SpelExpressionParser();
|
||||
private static final EvaluationContextProvider EVALUATION_CONTEXT_PROVIDER = DefaultEvaluationContextProvider.INSTANCE;
|
||||
|
||||
JpaQueryMethod method;
|
||||
|
||||
@@ -95,8 +99,8 @@ public class SimpleJpaQueryUnitTests {
|
||||
when(method.getEntityInformation()).thenReturn((JpaEntityMetadata) new DefaultJpaEntityMetadata<User>(User.class));
|
||||
when(em.createQuery("foo", Long.class)).thenReturn(query);
|
||||
|
||||
SimpleJpaQuery jpaQuery = new SimpleJpaQuery(method, em, "select u from User u",
|
||||
DefaultEvaluationContextProvider.INSTANCE);
|
||||
SimpleJpaQuery jpaQuery = new SimpleJpaQuery(method, em, "select u from User u", EVALUATION_CONTEXT_PROVIDER,
|
||||
PARSER);
|
||||
|
||||
assertThat(jpaQuery.createCountQuery(new Object[] {}), is(query));
|
||||
}
|
||||
@@ -113,7 +117,7 @@ public class SimpleJpaQueryUnitTests {
|
||||
JpaQueryMethod queryMethod = new JpaQueryMethod(method, metadata, extractor);
|
||||
|
||||
AbstractJpaQuery jpaQuery = new SimpleJpaQuery(queryMethod, em, "select u from User u",
|
||||
DefaultEvaluationContextProvider.INSTANCE);
|
||||
EVALUATION_CONTEXT_PROVIDER, PARSER);
|
||||
jpaQuery.createCountQuery(new Object[] { new PageRequest(1, 10) });
|
||||
|
||||
verify(query, times(0)).setFirstResult(anyInt());
|
||||
@@ -127,7 +131,7 @@ public class SimpleJpaQueryUnitTests {
|
||||
Method method = SampleRepository.class.getMethod("findNativeByLastname", String.class);
|
||||
JpaQueryMethod queryMethod = new JpaQueryMethod(method, metadata, extractor);
|
||||
AbstractJpaQuery jpaQuery = JpaQueryFactory.INSTANCE.fromQueryAnnotation(queryMethod, em,
|
||||
DefaultEvaluationContextProvider.INSTANCE);
|
||||
EVALUATION_CONTEXT_PROVIDER);
|
||||
|
||||
assertThat(jpaQuery instanceof NativeJpaQuery, is(true));
|
||||
|
||||
@@ -208,8 +212,7 @@ public class SimpleJpaQueryUnitTests {
|
||||
private RepositoryQuery createJpaQuery(Method method) {
|
||||
|
||||
JpaQueryMethod queryMethod = new JpaQueryMethod(method, metadata, extractor);
|
||||
return JpaQueryFactory.INSTANCE.fromQueryAnnotation(queryMethod, em,
|
||||
DefaultEvaluationContextProvider.INSTANCE);
|
||||
return JpaQueryFactory.INSTANCE.fromQueryAnnotation(queryMethod, em, EVALUATION_CONTEXT_PROVIDER);
|
||||
}
|
||||
|
||||
interface SampleRepository {
|
||||
|
||||
Reference in New Issue
Block a user