2525import org .bson .Document ;
2626import org .bson .codecs .configuration .CodecRegistry ;
2727import org .reactivestreams .Publisher ;
28+
2829import org .springframework .core .convert .converter .Converter ;
30+ import org .springframework .data .expression .ValueExpression ;
2931import org .springframework .data .mapping .model .EntityInstantiators ;
3032import org .springframework .data .mapping .model .SpELExpressionEvaluator ;
33+ import org .springframework .data .mapping .model .ValueExpressionEvaluator ;
3134import org .springframework .data .mongodb .core .MongoOperations ;
3235import org .springframework .data .mongodb .core .ReactiveFindOperation .FindWithProjection ;
3336import org .springframework .data .mongodb .core .ReactiveFindOperation .FindWithQuery ;
4851import org .springframework .data .mongodb .util .json .ParameterBindingContext ;
4952import org .springframework .data .mongodb .util .json .ParameterBindingDocumentCodec ;
5053import org .springframework .data .repository .query .ParameterAccessor ;
51- import org .springframework .data .repository .query .ReactiveQueryMethodEvaluationContextProvider ;
54+ import org .springframework .data .repository .query .ReactiveQueryMethodValueEvaluationContextProvider ;
5255import org .springframework .data .repository .query .RepositoryQuery ;
5356import org .springframework .data .repository .query .ResultProcessor ;
57+ import org .springframework .data .repository .query .ValueExpressionSupportHolder ;
5458import org .springframework .data .spel .ExpressionDependencies ;
5559import org .springframework .data .util .TypeInformation ;
56- import org .springframework .expression .ExpressionParser ;
60+ import org .springframework .expression .spel . standard . SpelExpressionParser ;
5761import org .springframework .lang .Nullable ;
5862import org .springframework .util .Assert ;
5963import org .springframework .util .ObjectUtils ;
@@ -76,31 +80,30 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
7680 private final EntityInstantiators instantiators ;
7781 private final FindWithProjection <?> findOperationWithProjection ;
7882 private final ReactiveUpdate <?> updateOps ;
79- private final ExpressionParser expressionParser ;
80- private final ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider ;
83+ private final ValueExpressionSupportHolder expressionSupportHolder ;
84+ private final ReactiveQueryMethodValueEvaluationContextProvider evaluationContextProvider ;
8185
8286 /**
8387 * Creates a new {@link AbstractReactiveMongoQuery} from the given {@link MongoQueryMethod} and
8488 * {@link MongoOperations}.
8589 *
8690 * @param method must not be {@literal null}.
8791 * @param operations must not be {@literal null}.
88- * @param expressionParser must not be {@literal null}.
89- * @param evaluationContextProvider must not be {@literal null}.
92+ * @param expressionSupportHolder must not be {@literal null}.
9093 */
9194 public AbstractReactiveMongoQuery (ReactiveMongoQueryMethod method , ReactiveMongoOperations operations ,
92- ExpressionParser expressionParser , ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider ) {
95+ ValueExpressionSupportHolder expressionSupportHolder ) {
9396
9497 Assert .notNull (method , "MongoQueryMethod must not be null" );
9598 Assert .notNull (operations , "ReactiveMongoOperations must not be null" );
96- Assert .notNull (expressionParser , "SpelExpressionParser must not be null" );
97- Assert .notNull (evaluationContextProvider , "ReactiveEvaluationContextExtension must not be null" );
99+ Assert .notNull (expressionSupportHolder , "ValueExpressionSupportHolder must not be null" );
98100
99101 this .method = method ;
100102 this .operations = operations ;
101103 this .instantiators = new EntityInstantiators ();
102- this .expressionParser = expressionParser ;
103- this .evaluationContextProvider = evaluationContextProvider ;
104+ this .expressionSupportHolder = expressionSupportHolder ;
105+ this .evaluationContextProvider = (ReactiveQueryMethodValueEvaluationContextProvider ) expressionSupportHolder
106+ .createValueContextProvider (method .getParameters ());
104107
105108 MongoEntityMetadata <?> metadata = method .getEntityInformation ();
106109 Class <?> type = metadata .getCollectionEntity ().getType ();
@@ -231,7 +234,6 @@ private boolean isTailable(MongoQueryMethod method) {
231234 return method .getTailableAnnotation () != null ;
232235 }
233236
234-
235237 Query applyQueryMetaAttributesWhenPresent (Query query ) {
236238
237239 if (method .hasQueryMetaAttributes ()) {
@@ -270,7 +272,7 @@ Query applyAnnotatedDefaultSortIfPresent(Query query) {
270272 Query applyAnnotatedCollationIfPresent (Query query , ConvertingParameterAccessor accessor ) {
271273
272274 return QueryUtils .applyCollation (query , method .hasAnnotatedCollation () ? method .getAnnotatedCollation () : null ,
273- accessor , getQueryMethod (). getParameters (), expressionParser , evaluationContextProvider );
275+ accessor , getValueExpressionEvaluator ( accessor ) );
274276 }
275277
276278 /**
@@ -290,7 +292,8 @@ Query applyHintIfPresent(Query query) {
290292 }
291293
292294 /**
293- * If present apply the {@link com.mongodb.ReadPreference} from the {@link org.springframework.data.mongodb.repository.ReadPreference} annotation.
295+ * If present apply the {@link com.mongodb.ReadPreference} from the
296+ * {@link org.springframework.data.mongodb.repository.ReadPreference} annotation.
294297 *
295298 * @param query must not be {@literal null}.
296299 * @return never {@literal null}.
@@ -382,15 +385,15 @@ private Mono<AggregationOperation> computePipelineStage(String source, MongoPara
382385 });
383386 }
384387
385- private Mono <Tuple2 <SpELExpressionEvaluator , ParameterBindingDocumentCodec >> expressionEvaluator (String source ,
388+ private Mono <Tuple2 <ValueExpressionEvaluator , ParameterBindingDocumentCodec >> expressionEvaluator (String source ,
386389 MongoParameterAccessor accessor , ParameterBindingDocumentCodec codec ) {
387390
388391 ExpressionDependencies dependencies = codec .captureExpressionDependencies (source , accessor ::getBindableValue ,
389- expressionParser );
390- return getSpelEvaluatorFor (dependencies , accessor ).zipWith (Mono .just (codec ));
392+ expressionSupportHolder . getValueExpressionParser () );
393+ return getValueExpressionEvaluatorLater (dependencies , accessor ).zipWith (Mono .just (codec ));
391394 }
392395
393- private Document decode (SpELExpressionEvaluator expressionEvaluator , String source , MongoParameterAccessor accessor ,
396+ private Document decode (ValueExpressionEvaluator expressionEvaluator , String source , MongoParameterAccessor accessor ,
394397 ParameterBindingDocumentCodec codec ) {
395398
396399 ParameterBindingContext bindingContext = new ParameterBindingContext (accessor ::getBindableValue ,
@@ -420,13 +423,60 @@ protected Mono<ParameterBindingDocumentCodec> getParameterBindingCodec() {
420423 protected Mono <SpELExpressionEvaluator > getSpelEvaluatorFor (ExpressionDependencies dependencies ,
421424 MongoParameterAccessor accessor ) {
422425
423- return evaluationContextProvider
424- .getEvaluationContextLater (getQueryMethod ().getParameters (), accessor .getValues (), dependencies )
425- .map (evaluationContext -> (SpELExpressionEvaluator ) new DefaultSpELExpressionEvaluator (expressionParser ,
426- evaluationContext ))
426+ return evaluationContextProvider .getEvaluationContextLater (accessor .getValues (), dependencies )
427+ .map (evaluationContext -> (SpELExpressionEvaluator ) new DefaultSpELExpressionEvaluator (
428+ new SpelExpressionParser (), evaluationContext .getEvaluationContext ()))
427429 .defaultIfEmpty (DefaultSpELExpressionEvaluator .unsupported ());
428430 }
429431
432+ /**
433+ * Obtain a {@link ValueExpressionEvaluator} suitable to evaluate expressions.
434+ *
435+ * @param accessor must not be {@literal null}.
436+ * @since 4.3
437+ */
438+ ValueExpressionEvaluator getValueExpressionEvaluator (MongoParameterAccessor accessor ) {
439+
440+ return new ValueExpressionEvaluator () {
441+
442+ @ Override
443+ public <T > T evaluate (String expressionString ) {
444+
445+ ValueExpression expression = expressionSupportHolder .parse (expressionString );
446+ return (T ) expression .evaluate (evaluationContextProvider .getEvaluationContext (accessor .getValues (),
447+ expression .getExpressionDependencies ()));
448+ }
449+ };
450+ }
451+
452+ /**
453+ * Obtain a {@link Mono publisher} emitting the {@link ValueExpressionEvaluator} suitable to evaluate expressions
454+ * backed by the given dependencies.
455+ *
456+ * @param dependencies must not be {@literal null}.
457+ * @param accessor must not be {@literal null}.
458+ * @return a {@link Mono} emitting the {@link ValueExpressionEvaluator} when ready.
459+ * @since 4.3
460+ */
461+ protected Mono <ValueExpressionEvaluator > getValueExpressionEvaluatorLater (ExpressionDependencies dependencies ,
462+ MongoParameterAccessor accessor ) {
463+
464+ return evaluationContextProvider .getEvaluationContextLater (accessor .getValues (), dependencies )
465+ .map (evaluationContext -> {
466+
467+ return new ValueExpressionEvaluator () {
468+ @ Override
469+ public <T > T evaluate (String expressionString ) {
470+
471+ ValueExpression expression = expressionSupportHolder .parse (expressionString );
472+
473+ return (T ) expression .evaluate (evaluationContext );
474+ }
475+ };
476+
477+ });
478+ }
479+
430480 /**
431481 * @return a {@link Mono} emitting the {@link CodecRegistry} when ready.
432482 * @since 2.4
0 commit comments