Browse Source

DATAMONGO-1894 - Introduce cached ExpressionParser.

Original Pull Request: #874
pull/879/head
Mark Paluch 6 years ago committed by Christoph Strobl
parent
commit
41607b10d0
  1. 5
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java
  2. 5
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java
  3. 7
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AggregationUtils.java
  4. 3
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/CollationUtils.java
  5. 25
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/DefaultSpELExpressionEvaluator.java
  6. 34
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/NoOpExpressionEvaluator.java
  7. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/PartTreeMongoQuery.java
  8. 3
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/QueryUtils.java
  9. 3
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactivePartTreeMongoQuery.java
  10. 13
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveStringBasedAggregation.java
  11. 8
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveStringBasedMongoQuery.java
  12. 6
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/StringBasedAggregation.java
  13. 8
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/StringBasedMongoQuery.java
  14. 59
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/CachingExpressionParser.java
  15. 12
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MongoRepositoryFactory.java
  16. 10
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveMongoRepositoryFactory.java
  17. 5
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingContext.java
  18. 1
      src/main/asciidoc/new-features.adoc
  19. 8
      src/main/asciidoc/reference/mongo-repositories.adoc

5
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java

@ -30,6 +30,7 @@ import org.springframework.data.repository.query.ParameterAccessor; @@ -30,6 +30,7 @@ import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@ -47,7 +48,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery { @@ -47,7 +48,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
private final MongoQueryMethod method;
private final MongoOperations operations;
private final ExecutableFind<?> executableFind;
private final SpelExpressionParser expressionParser;
private final ExpressionParser expressionParser;
private final QueryMethodEvaluationContextProvider evaluationContextProvider;
/**
@ -58,7 +59,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery { @@ -58,7 +59,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
* @param expressionParser must not be {@literal null}.
* @param evaluationContextProvider must not be {@literal null}.
*/
public AbstractMongoQuery(MongoQueryMethod method, MongoOperations operations, SpelExpressionParser expressionParser,
public AbstractMongoQuery(MongoQueryMethod method, MongoOperations operations, ExpressionParser expressionParser,
QueryMethodEvaluationContextProvider evaluationContextProvider) {
Assert.notNull(operations, "MongoOperations must not be null!");

5
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java

@ -37,6 +37,7 @@ import org.springframework.data.repository.query.ReactiveQueryMethodEvaluationCo @@ -37,6 +37,7 @@ import org.springframework.data.repository.query.ReactiveQueryMethodEvaluationCo
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.util.TypeInformation;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@ -54,7 +55,7 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery { @@ -54,7 +55,7 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
private final ReactiveMongoOperations operations;
private final EntityInstantiators instantiators;
private final FindWithProjection<?> findOperationWithProjection;
private final SpelExpressionParser expressionParser;
private final ExpressionParser expressionParser;
private final ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider;
/**
@ -67,7 +68,7 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery { @@ -67,7 +68,7 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
* @param evaluationContextProvider must not be {@literal null}.
*/
public AbstractReactiveMongoQuery(ReactiveMongoQueryMethod method, ReactiveMongoOperations operations,
SpelExpressionParser expressionParser, ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider) {
ExpressionParser expressionParser, ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider) {
Assert.notNull(method, "MongoQueryMethod must not be null!");
Assert.notNull(operations, "ReactiveMongoOperations must not be null!");

7
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AggregationUtils.java

@ -34,6 +34,7 @@ import org.springframework.data.mongodb.core.query.Query; @@ -34,6 +34,7 @@ import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.util.json.ParameterBindingContext;
import org.springframework.data.mongodb.util.json.ParameterBindingDocumentCodec;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
@ -64,12 +65,12 @@ abstract class AggregationUtils { @@ -64,12 +65,12 @@ abstract class AggregationUtils {
* @param accessor must not be {@literal null}.
* @return the {@link Query} having proper {@link Collation}.
* @see AggregationOptions#getCollation()
* @see CollationUtils#computeCollation(String, ConvertingParameterAccessor, MongoParameters, SpelExpressionParser,
* @see CollationUtils#computeCollation(String, ConvertingParameterAccessor, MongoParameters, ExpressionParser,
* QueryMethodEvaluationContextProvider)
*/
static AggregationOptions.Builder applyCollation(AggregationOptions.Builder builder,
@Nullable String collationExpression, ConvertingParameterAccessor accessor, MongoParameters parameters,
SpelExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
ExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
Collation collation = CollationUtils.computeCollation(collationExpression, accessor, parameters, expressionParser,
evaluationContextProvider);
@ -119,7 +120,7 @@ abstract class AggregationUtils { @@ -119,7 +120,7 @@ abstract class AggregationUtils {
* @return
*/
static List<AggregationOperation> computePipeline(MongoQueryMethod method, ConvertingParameterAccessor accessor,
SpelExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
ExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
ParameterBindingContext bindingContext = new ParameterBindingContext((accessor::getBindableValue), expressionParser,
() -> evaluationContextProvider.getEvaluationContext(method.getParameters(), accessor.getValues()));

3
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/CollationUtils.java

@ -24,6 +24,7 @@ import org.springframework.data.mongodb.core.query.Collation; @@ -24,6 +24,7 @@ import org.springframework.data.mongodb.core.query.Collation;
import org.springframework.data.mongodb.util.json.ParameterBindingContext;
import org.springframework.data.mongodb.util.json.ParameterBindingDocumentCodec;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
import org.springframework.util.NumberUtils;
@ -59,7 +60,7 @@ abstract class CollationUtils { @@ -59,7 +60,7 @@ abstract class CollationUtils {
*/
@Nullable
static Collation computeCollation(@Nullable String collationExpression, ConvertingParameterAccessor accessor,
MongoParameters parameters, SpelExpressionParser expressionParser,
MongoParameters parameters, ExpressionParser expressionParser,
QueryMethodEvaluationContextProvider evaluationContextProvider) {
if (accessor.getCollation() != null) {

25
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/DefaultSpELExpressionEvaluator.java

@ -35,6 +35,15 @@ class DefaultSpELExpressionEvaluator implements SpELExpressionEvaluator { @@ -35,6 +35,15 @@ class DefaultSpELExpressionEvaluator implements SpELExpressionEvaluator {
this.context = context;
}
/**
* Return a {@link SpELExpressionEvaluator} that does not support expression evaluation.
*
* @return a {@link SpELExpressionEvaluator} that does not support expression evaluation.
*/
public static SpELExpressionEvaluator unsupported() {
return NoOpExpressionEvaluator.INSTANCE;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.model.SpELExpressionEvaluator#evaluate(java.lang.String)
@ -44,4 +53,20 @@ class DefaultSpELExpressionEvaluator implements SpELExpressionEvaluator { @@ -44,4 +53,20 @@ class DefaultSpELExpressionEvaluator implements SpELExpressionEvaluator {
public <T> T evaluate(String expression) {
return (T) parser.parseExpression(expression).getValue(context, Object.class);
}
/**
* {@link SpELExpressionEvaluator} that does not support SpEL evaluation.
*
* @author Mark Paluch
* @since 3.1
*/
enum NoOpExpressionEvaluator implements SpELExpressionEvaluator {
INSTANCE;
@Override
public <T> T evaluate(String expression) {
throw new UnsupportedOperationException("Expression evaluation not supported");
}
}
}

34
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/NoOpExpressionEvaluator.java

@ -1,34 +0,0 @@ @@ -1,34 +0,0 @@
/*
* Copyright 2020 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.mongodb.repository.query;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
/**
* {@link SpELExpressionEvaluator} that does not support SpEL evaluation.
*
* @author Mark Paluch
* @since 3.1
*/
enum NoOpExpressionEvaluator implements SpELExpressionEvaluator {
INSTANCE;
@Override
public <T> T evaluate(String expression) {
throw new UnsupportedOperationException("Expression evaluation not supported");
}
}

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/PartTreeMongoQuery.java

@ -32,7 +32,7 @@ import org.springframework.data.repository.query.RepositoryQuery; @@ -32,7 +32,7 @@ import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.ExpressionParser;
import org.springframework.util.StringUtils;
/**
@ -59,7 +59,7 @@ public class PartTreeMongoQuery extends AbstractMongoQuery { @@ -59,7 +59,7 @@ public class PartTreeMongoQuery extends AbstractMongoQuery {
* @param evaluationContextProvider must not be {@literal null}.
*/
public PartTreeMongoQuery(MongoQueryMethod method, MongoOperations mongoOperations,
SpelExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
ExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
super(method, mongoOperations, expressionParser, evaluationContextProvider);

3
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/QueryUtils.java

@ -21,6 +21,7 @@ import org.springframework.aop.framework.ProxyFactory; @@ -21,6 +21,7 @@ import org.springframework.aop.framework.ProxyFactory;
import org.springframework.data.mongodb.core.query.Collation;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
@ -76,7 +77,7 @@ class QueryUtils { @@ -76,7 +77,7 @@ class QueryUtils {
* @since 2.2
*/
static Query applyCollation(Query query, @Nullable String collationExpression, ConvertingParameterAccessor accessor,
MongoParameters parameters, SpelExpressionParser expressionParser,
MongoParameters parameters, ExpressionParser expressionParser,
QueryMethodEvaluationContextProvider evaluationContextProvider) {
Collation collation = CollationUtils.computeCollation(collationExpression, accessor, parameters, expressionParser,

3
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactivePartTreeMongoQuery.java

@ -33,6 +33,7 @@ import org.springframework.data.repository.query.RepositoryQuery; @@ -33,6 +33,7 @@ import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.util.StringUtils;
@ -59,7 +60,7 @@ public class ReactivePartTreeMongoQuery extends AbstractReactiveMongoQuery { @@ -59,7 +60,7 @@ public class ReactivePartTreeMongoQuery extends AbstractReactiveMongoQuery {
* @param evaluationContextProvider must not be {@literal null}.
*/
public ReactivePartTreeMongoQuery(ReactiveMongoQueryMethod method, ReactiveMongoOperations mongoOperations,
SpelExpressionParser expressionParser, ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider) {
ExpressionParser expressionParser, ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider) {
super(method, mongoOperations, expressionParser, evaluationContextProvider);

13
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveStringBasedAggregation.java

@ -39,6 +39,7 @@ import org.springframework.data.mongodb.util.json.ParameterBindingDocumentCodec; @@ -39,6 +39,7 @@ import org.springframework.data.mongodb.util.json.ParameterBindingDocumentCodec;
import org.springframework.data.repository.query.ReactiveQueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.spel.ExpressionDependencies;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.util.ClassUtils;
@ -54,7 +55,7 @@ public class ReactiveStringBasedAggregation extends AbstractReactiveMongoQuery { @@ -54,7 +55,7 @@ public class ReactiveStringBasedAggregation extends AbstractReactiveMongoQuery {
private static final ParameterBindingDocumentCodec CODEC = new ParameterBindingDocumentCodec();
private final SpelExpressionParser expressionParser;
private final ExpressionParser expressionParser;
private final ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider;
private final ReactiveMongoOperations reactiveMongoOperations;
private final MongoConverter mongoConverter;
@ -66,7 +67,7 @@ public class ReactiveStringBasedAggregation extends AbstractReactiveMongoQuery { @@ -66,7 +67,7 @@ public class ReactiveStringBasedAggregation extends AbstractReactiveMongoQuery {
* @param evaluationContextProvider must not be {@literal null}.
*/
public ReactiveStringBasedAggregation(ReactiveMongoQueryMethod method,
ReactiveMongoOperations reactiveMongoOperations, SpelExpressionParser expressionParser,
ReactiveMongoOperations reactiveMongoOperations, ExpressionParser expressionParser,
ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider) {
super(method, reactiveMongoOperations, expressionParser, evaluationContextProvider);
@ -118,11 +119,7 @@ public class ReactiveStringBasedAggregation extends AbstractReactiveMongoQuery { @@ -118,11 +119,7 @@ public class ReactiveStringBasedAggregation extends AbstractReactiveMongoQuery {
});
}
if (method.isCollectionQuery()) {
return flux;
} else {
return flux.next();
}
return method.isCollectionQuery() ? flux : flux.next();
});
}
@ -145,7 +142,7 @@ public class ReactiveStringBasedAggregation extends AbstractReactiveMongoQuery { @@ -145,7 +142,7 @@ public class ReactiveStringBasedAggregation extends AbstractReactiveMongoQuery {
it -> evaluationContextProvider.getEvaluationContextLater(method.getParameters(), accessor.getValues(), it))
.map(evaluationContext -> evaluationContext
.map(it -> (SpELExpressionEvaluator) new DefaultSpELExpressionEvaluator(expressionParser, it)))
.orElseGet(() -> Mono.just(NoOpExpressionEvaluator.INSTANCE));
.orElseGet(() -> Mono.just(DefaultSpELExpressionEvaluator.unsupported()));
Mono<AggregationOperation> stage = evaluator.map(it -> {

8
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/ReactiveStringBasedMongoQuery.java

@ -53,7 +53,7 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery { @@ -53,7 +53,7 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery {
private final String query;
private final String fieldSpec;
private final SpelExpressionParser expressionParser;
private final ExpressionParser expressionParser;
private final ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider;
private final boolean isCountQuery;
@ -70,7 +70,7 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery { @@ -70,7 +70,7 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery {
* @param evaluationContextProvider must not be {@literal null}.
*/
public ReactiveStringBasedMongoQuery(ReactiveMongoQueryMethod method, ReactiveMongoOperations mongoOperations,
SpelExpressionParser expressionParser, ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider) {
ExpressionParser expressionParser, ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider) {
this(method.getAnnotatedQuery(), method, mongoOperations, expressionParser, evaluationContextProvider);
}
@ -85,7 +85,7 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery { @@ -85,7 +85,7 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery {
* @param expressionParser must not be {@literal null}.
*/
public ReactiveStringBasedMongoQuery(String query, ReactiveMongoQueryMethod method,
ReactiveMongoOperations mongoOperations, SpelExpressionParser expressionParser,
ReactiveMongoOperations mongoOperations, ExpressionParser expressionParser,
ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider) {
super(method, mongoOperations, expressionParser, evaluationContextProvider);
@ -153,7 +153,7 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery { @@ -153,7 +153,7 @@ public class ReactiveStringBasedMongoQuery extends AbstractReactiveMongoQuery {
accessor.getValues(), it))
.map(evaluationContext -> evaluationContext
.map(it -> (SpELExpressionEvaluator) new DefaultSpELExpressionEvaluator(expressionParser, it)))
.orElseGet(() -> Mono.just(NoOpExpressionEvaluator.INSTANCE));
.orElseGet(() -> Mono.just(DefaultSpELExpressionEvaluator.unsupported()));
return evaluator.map(it -> new ParameterBindingContext(accessor::getBindableValue, it));
}

6
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/StringBasedAggregation.java

@ -32,7 +32,7 @@ import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes; @@ -32,7 +32,7 @@ import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.ExpressionParser;
import org.springframework.util.ClassUtils;
/**
@ -43,7 +43,7 @@ public class StringBasedAggregation extends AbstractMongoQuery { @@ -43,7 +43,7 @@ public class StringBasedAggregation extends AbstractMongoQuery {
private final MongoOperations mongoOperations;
private final MongoConverter mongoConverter;
private final SpelExpressionParser expressionParser;
private final ExpressionParser expressionParser;
private final QueryMethodEvaluationContextProvider evaluationContextProvider;
/**
@ -55,7 +55,7 @@ public class StringBasedAggregation extends AbstractMongoQuery { @@ -55,7 +55,7 @@ public class StringBasedAggregation extends AbstractMongoQuery {
* @param evaluationContextProvider
*/
public StringBasedAggregation(MongoQueryMethod method, MongoOperations mongoOperations,
SpelExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
ExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
super(method, mongoOperations, expressionParser, evaluationContextProvider);
this.mongoOperations = mongoOperations;

8
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/StringBasedMongoQuery.java

@ -54,7 +54,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery { @@ -54,7 +54,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
private final String fieldSpec;
private final ParameterBindingDocumentCodec codec;
private final SpelExpressionParser expressionParser;
private final ExpressionParser expressionParser;
private final QueryMethodEvaluationContextProvider evaluationContextProvider;
private final boolean isCountQuery;
@ -71,7 +71,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery { @@ -71,7 +71,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
* @param evaluationContextProvider must not be {@literal null}.
*/
public StringBasedMongoQuery(MongoQueryMethod method, MongoOperations mongoOperations,
SpelExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
ExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
this(method.getAnnotatedQuery(), method, mongoOperations, expressionParser, evaluationContextProvider);
}
@ -85,7 +85,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery { @@ -85,7 +85,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
* @param expressionParser must not be {@literal null}.
*/
public StringBasedMongoQuery(String query, MongoQueryMethod method, MongoOperations mongoOperations,
SpelExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
ExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
super(method, mongoOperations, expressionParser, evaluationContextProvider);
@ -151,7 +151,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery { @@ -151,7 +151,7 @@ public class StringBasedMongoQuery extends AbstractMongoQuery {
accessor.getValues(), it))
.map(evaluationContext -> (SpELExpressionEvaluator) new DefaultSpELExpressionEvaluator(expressionParser,
evaluationContext))
.orElse(NoOpExpressionEvaluator.INSTANCE);
.orElse(DefaultSpELExpressionEvaluator.unsupported());
return new ParameterBindingContext(accessor::getBindableValue, evaluator);
}

59
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/CachingExpressionParser.java

@ -0,0 +1,59 @@ @@ -0,0 +1,59 @@
/*
* Copyright 2020 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.mongodb.repository.support;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
/**
* Caching variant of {@link ExpressionParser}. This implementation does not support
* {@link #parseExpression(String, ParserContext) parsing with ParseContext}.
*
* @author Mark Paluch
* @since 3.1
*/
class CachingExpressionParser implements ExpressionParser {
private final ExpressionParser delegate;
private final Map<String, Expression> cache = new ConcurrentHashMap<>();
public CachingExpressionParser(ExpressionParser delegate) {
this.delegate = delegate;
}
/*
* (non-Javadoc)
* @see org.springframework.expression.ExpressionParser#parseExpression(java.lang.String)
*/
@Override
public Expression parseExpression(String expressionString) throws ParseException {
return cache.computeIfAbsent(expressionString, delegate::parseExpression);
}
/*
* (non-Javadoc)
* @see org.springframework.expression.ExpressionParser#parseExpression(java.lang.String, org.springframework.expression.ParserContext)
*/
@Override
public Expression parseExpression(String expressionString, ParserContext context) throws ParseException {
throw new UnsupportedOperationException("Parsing using ParserContext is not supported");
}
}

12
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/MongoRepositoryFactory.java

@ -44,6 +44,7 @@ import org.springframework.data.repository.query.QueryLookupStrategy; @@ -44,6 +44,7 @@ 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.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@ -162,7 +163,8 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport { @@ -162,7 +163,8 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
private final MongoOperations operations;
private final QueryMethodEvaluationContextProvider evaluationContextProvider;
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
private final ExpressionParser expressionParser = new CachingExpressionParser(EXPRESSION_PARSER);
public MongoQueryLookupStrategy(MongoOperations operations,
QueryMethodEvaluationContextProvider evaluationContextProvider,
@ -186,14 +188,14 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport { @@ -186,14 +188,14 @@ public class MongoRepositoryFactory extends RepositoryFactorySupport {
if (namedQueries.hasQuery(namedQueryName)) {
String namedQuery = namedQueries.getQuery(namedQueryName);
return new StringBasedMongoQuery(namedQuery, queryMethod, operations, EXPRESSION_PARSER,
return new StringBasedMongoQuery(namedQuery, queryMethod, operations, expressionParser,
evaluationContextProvider);
} else if (queryMethod.hasAnnotatedAggregation()) {
return new StringBasedAggregation(queryMethod, operations, EXPRESSION_PARSER, evaluationContextProvider);
return new StringBasedAggregation(queryMethod, operations, expressionParser, evaluationContextProvider);
} else if (queryMethod.hasAnnotatedQuery()) {
return new StringBasedMongoQuery(queryMethod, operations, EXPRESSION_PARSER, evaluationContextProvider);
return new StringBasedMongoQuery(queryMethod, operations, expressionParser, evaluationContextProvider);
} else {
return new PartTreeMongoQuery(queryMethod, operations, EXPRESSION_PARSER, evaluationContextProvider);
return new PartTreeMongoQuery(queryMethod, operations, expressionParser, evaluationContextProvider);
}
}
}

10
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveMongoRepositoryFactory.java

@ -44,6 +44,7 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key; @@ -44,6 +44,7 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.ReactiveQueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@ -161,6 +162,7 @@ public class ReactiveMongoRepositoryFactory extends ReactiveRepositoryFactorySup @@ -161,6 +162,7 @@ public class ReactiveMongoRepositoryFactory extends ReactiveRepositoryFactorySup
private final ReactiveMongoOperations operations;
private final ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider;
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
private final ExpressionParser expressionParser = new CachingExpressionParser(EXPRESSION_PARSER);
MongoQueryLookupStrategy(ReactiveMongoOperations operations,
ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider,
@ -184,15 +186,15 @@ public class ReactiveMongoRepositoryFactory extends ReactiveRepositoryFactorySup @@ -184,15 +186,15 @@ public class ReactiveMongoRepositoryFactory extends ReactiveRepositoryFactorySup
if (namedQueries.hasQuery(namedQueryName)) {
String namedQuery = namedQueries.getQuery(namedQueryName);
return new ReactiveStringBasedMongoQuery(namedQuery, queryMethod, operations, EXPRESSION_PARSER,
return new ReactiveStringBasedMongoQuery(namedQuery, queryMethod, operations, expressionParser,
evaluationContextProvider);
} else if (queryMethod.hasAnnotatedAggregation()) {
return new ReactiveStringBasedAggregation(queryMethod, operations, EXPRESSION_PARSER,
return new ReactiveStringBasedAggregation(queryMethod, operations, expressionParser,
evaluationContextProvider);
} else if (queryMethod.hasAnnotatedQuery()) {
return new ReactiveStringBasedMongoQuery(queryMethod, operations, EXPRESSION_PARSER, evaluationContextProvider);
return new ReactiveStringBasedMongoQuery(queryMethod, operations, expressionParser, evaluationContextProvider);
} else {
return new ReactivePartTreeMongoQuery(queryMethod, operations, EXPRESSION_PARSER, evaluationContextProvider);
return new ReactivePartTreeMongoQuery(queryMethod, operations, expressionParser, evaluationContextProvider);
}
}
}

5
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingContext.java

@ -23,6 +23,7 @@ import org.springframework.data.spel.ExpressionDependencies; @@ -23,6 +23,7 @@ import org.springframework.data.spel.ExpressionDependencies;
import org.springframework.data.util.Lazy;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
@ -55,7 +56,7 @@ public class ParameterBindingContext { @@ -55,7 +56,7 @@ public class ParameterBindingContext {
* @param evaluationContext a {@link Supplier} for {@link Lazy} context retrieval.
* @since 2.2.3
*/
public ParameterBindingContext(ValueProvider valueProvider, SpelExpressionParser expressionParser,
public ParameterBindingContext(ValueProvider valueProvider, ExpressionParser expressionParser,
Supplier<EvaluationContext> evaluationContext) {
this(valueProvider, new SpELExpressionEvaluator() {
@ -87,7 +88,7 @@ public class ParameterBindingContext { @@ -87,7 +88,7 @@ public class ParameterBindingContext {
* @since 3.1
*/
public static ParameterBindingContext forExpressions(ValueProvider valueProvider,
SpelExpressionParser expressionParser, Function<ExpressionDependencies, EvaluationContext> contextFunction) {
ExpressionParser expressionParser, Function<ExpressionDependencies, EvaluationContext> contextFunction) {
return new ParameterBindingContext(valueProvider, new SpELExpressionEvaluator() {
@Override

1
src/main/asciidoc/new-features.adoc

@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
== What's New in Spring Data MongoDB 3.1
* <<mongo.auditing,Reactive auditing>> enabled through `@EnableReactiveMongoAuditing`. `@EnableMongoAuditing` no longer registers `ReactiveAuditingEntityCallback`.
* Reactive SpEL support in `@Query` and `@Aggregation` query methods.
[[new-features.3.0]]
== What's New in Spring Data MongoDB 3.0

8
src/main/asciidoc/reference/mongo-repositories.adoc

@ -492,13 +492,15 @@ public class SampleEvaluationContextExtension extends EvaluationContextExtension @@ -492,13 +492,15 @@ public class SampleEvaluationContextExtension extends EvaluationContextExtension
}
----
NOTE: Bootstrapping `MongoRepositoryFactory` yourself is not application context-aware and requires further configuration
to pick up Query SPI extensions.
NOTE: Bootstrapping `MongoRepositoryFactory` yourself is not application context-aware and requires further configuration to pick up Query SPI extensions.
NOTE: Reactive query methods can make use of `org.springframework.data.spel.spi.ReactiveEvaluationContextExtension`.
[[mongodb.repositories.queries.type-safe]]
=== Type-safe Query Methods
MongoDB repository support integrates with the http://www.querydsl.com/[Querydsl] project, which provides a way to perform type-safe queries. To quote from the project description, "Instead of writing queries as inline strings or externalizing them into XML files they are constructed via a fluent API." It provides the following features:
MongoDB repository support integrates with the http://www.querydsl.com/[Querydsl] project, which provides a way to perform type-safe queries.
To quote from the project description, "Instead of writing queries as inline strings or externalizing them into XML files they are constructed via a fluent API." It provides the following features:
* Code completion in the IDE (all properties, methods, and operations can be expanded in your favorite Java IDE).
* Almost no syntactically invalid queries allowed (type-safe on all levels).

Loading…
Cancel
Save