26
26
import org .reactivestreams .Publisher ;
27
27
28
28
import org .springframework .core .convert .converter .Converter ;
29
+ import org .springframework .core .env .StandardEnvironment ;
30
+ import org .springframework .data .expression .ReactiveValueEvaluationContextProvider ;
31
+ import org .springframework .data .expression .ValueEvaluationContext ;
32
+ import org .springframework .data .expression .ValueEvaluationContextProvider ;
33
+ import org .springframework .data .expression .ValueExpression ;
34
+ import org .springframework .data .expression .ValueExpressionParser ;
29
35
import org .springframework .data .mapping .model .EntityInstantiators ;
30
36
import org .springframework .data .mapping .model .SpELExpressionEvaluator ;
37
+ import org .springframework .data .mapping .model .ValueExpressionEvaluator ;
31
38
import org .springframework .data .mongodb .core .MongoOperations ;
32
39
import org .springframework .data .mongodb .core .ReactiveFindOperation .FindWithProjection ;
33
40
import org .springframework .data .mongodb .core .ReactiveFindOperation .FindWithQuery ;
48
55
import org .springframework .data .mongodb .util .json .ParameterBindingContext ;
49
56
import org .springframework .data .mongodb .util .json .ParameterBindingDocumentCodec ;
50
57
import org .springframework .data .repository .query .ParameterAccessor ;
58
+ import org .springframework .data .repository .query .QueryMethodValueEvaluationContextAccessor ;
51
59
import org .springframework .data .repository .query .ReactiveQueryMethodEvaluationContextProvider ;
52
60
import org .springframework .data .repository .query .RepositoryQuery ;
53
61
import org .springframework .data .repository .query .ResultProcessor ;
62
+ import org .springframework .data .repository .query .ValueExpressionDelegate ;
54
63
import org .springframework .data .spel .ExpressionDependencies ;
55
64
import org .springframework .data .util .TypeInformation ;
56
65
import org .springframework .expression .ExpressionParser ;
66
+ import org .springframework .expression .spel .standard .SpelExpressionParser ;
57
67
import org .springframework .lang .Nullable ;
58
68
import org .springframework .util .Assert ;
59
69
import org .springframework .util .ObjectUtils ;
60
70
import org .springframework .util .StringUtils ;
61
71
62
72
import com .mongodb .MongoClientSettings ;
73
+ import reactor .util .function .Tuple2 ;
63
74
64
75
/**
65
76
* Base class for reactive {@link RepositoryQuery} implementations for MongoDB.
@@ -76,8 +87,8 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
76
87
private final EntityInstantiators instantiators ;
77
88
private final FindWithProjection <?> findOperationWithProjection ;
78
89
private final ReactiveUpdate <?> updateOps ;
79
- private final ExpressionParser expressionParser ;
80
- private final ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider ;
90
+ private final ValueExpressionDelegate valueExpressionDelegate ;
91
+ private final ReactiveValueEvaluationContextProvider valueEvaluationContextProvider ;
81
92
82
93
/**
83
94
* Creates a new {@link AbstractReactiveMongoQuery} from the given {@link MongoQueryMethod} and
@@ -87,7 +98,9 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
87
98
* @param operations must not be {@literal null}.
88
99
* @param expressionParser must not be {@literal null}.
89
100
* @param evaluationContextProvider must not be {@literal null}.
101
+ * @deprecated use the constructor version with {@link ValueExpressionDelegate}
90
102
*/
103
+ @ Deprecated (since = "4.4.0" )
91
104
public AbstractReactiveMongoQuery (ReactiveMongoQueryMethod method , ReactiveMongoOperations operations ,
92
105
ExpressionParser expressionParser , ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider ) {
93
106
@@ -99,20 +112,57 @@ public AbstractReactiveMongoQuery(ReactiveMongoQueryMethod method, ReactiveMongo
99
112
this .method = method ;
100
113
this .operations = operations ;
101
114
this .instantiators = new EntityInstantiators ();
102
- this .expressionParser = expressionParser ;
103
- this .evaluationContextProvider = evaluationContextProvider ;
115
+ this .valueExpressionDelegate = new ValueExpressionDelegate (new QueryMethodValueEvaluationContextAccessor (new StandardEnvironment (), evaluationContextProvider .getEvaluationContextProvider ()), ValueExpressionParser .create (() -> expressionParser ));
104
116
105
117
MongoEntityMetadata <?> metadata = method .getEntityInformation ();
106
118
Class <?> type = metadata .getCollectionEntity ().getType ();
107
119
108
120
this .findOperationWithProjection = operations .query (type );
109
121
this .updateOps = operations .update (type );
122
+ ValueEvaluationContextProvider valueContextProvider = valueExpressionDelegate .createValueContextProvider (
123
+ method .getParameters ());
124
+ Assert .isInstanceOf (ReactiveValueEvaluationContextProvider .class , valueContextProvider , "ValueEvaluationContextProvider must be reactive" );
125
+ this .valueEvaluationContextProvider = (ReactiveValueEvaluationContextProvider ) valueContextProvider ;
110
126
}
111
127
128
+ /**
129
+ * Creates a new {@link AbstractReactiveMongoQuery} from the given {@link MongoQueryMethod} and
130
+ * {@link MongoOperations}.
131
+ *
132
+ * @param method must not be {@literal null}.
133
+ * @param operations must not be {@literal null}.
134
+ * @param delegate must not be {@literal null}.
135
+ * @since 4.4.0
136
+ */
137
+ public AbstractReactiveMongoQuery (ReactiveMongoQueryMethod method , ReactiveMongoOperations operations ,
138
+ ValueExpressionDelegate delegate ) {
139
+
140
+ Assert .notNull (method , "MongoQueryMethod must not be null" );
141
+ Assert .notNull (operations , "ReactiveMongoOperations must not be null" );
142
+ Assert .notNull (delegate , "ValueExpressionDelegate must not be null" );
143
+
144
+ this .method = method ;
145
+ this .operations = operations ;
146
+ this .instantiators = new EntityInstantiators ();
147
+ this .valueExpressionDelegate = delegate ;
148
+
149
+ MongoEntityMetadata <?> metadata = method .getEntityInformation ();
150
+ Class <?> type = metadata .getCollectionEntity ().getType ();
151
+
152
+ this .findOperationWithProjection = operations .query (type );
153
+ this .updateOps = operations .update (type );
154
+ ValueEvaluationContextProvider valueContextProvider = valueExpressionDelegate .createValueContextProvider (
155
+ method .getParameters ());
156
+ Assert .isInstanceOf (ReactiveValueEvaluationContextProvider .class , valueContextProvider , "ValueEvaluationContextProvider must be reactive" );
157
+ this .valueEvaluationContextProvider = (ReactiveValueEvaluationContextProvider ) valueContextProvider ;
158
+ }
159
+
160
+ @ Override
112
161
public MongoQueryMethod getQueryMethod () {
113
162
return method ;
114
163
}
115
164
165
+ @ Override
116
166
public Publisher <Object > execute (Object [] parameters ) {
117
167
118
168
return method .hasReactiveWrapperParameter () ? executeDeferred (parameters )
@@ -269,7 +319,7 @@ Query applyAnnotatedDefaultSortIfPresent(Query query) {
269
319
Query applyAnnotatedCollationIfPresent (Query query , ConvertingParameterAccessor accessor ) {
270
320
271
321
return QueryUtils .applyCollation (query , method .hasAnnotatedCollation () ? method .getAnnotatedCollation () : null ,
272
- accessor , getQueryMethod (). getParameters (), expressionParser , evaluationContextProvider );
322
+ accessor , getValueExpressionEvaluator ( accessor ) );
273
323
}
274
324
275
325
/**
@@ -381,19 +431,19 @@ private Mono<AggregationOperation> computePipelineStage(String source, MongoPara
381
431
bsonString -> AbstractReactiveMongoQuery .this .decode (evaluator , bsonString , accessor , codec )));
382
432
}
383
433
384
- private Mono <SpELExpressionEvaluator > expressionEvaluator (String source , MongoParameterAccessor accessor ,
385
- ParameterBindingDocumentCodec codec ) {
434
+ private Mono <Tuple2 < ValueExpressionEvaluator , ParameterBindingDocumentCodec >> expressionEvaluator (String source ,
435
+ MongoParameterAccessor accessor , ParameterBindingDocumentCodec codec ) {
386
436
387
437
ExpressionDependencies dependencies = codec .captureExpressionDependencies (source , accessor ::getBindableValue ,
388
- expressionParser );
389
- return getSpelEvaluatorFor (dependencies , accessor );
438
+ valueExpressionDelegate . getValueExpressionParser () );
439
+ return getValueExpressionEvaluatorLater (dependencies , accessor ). zipWith ( Mono . just ( codec ) );
390
440
}
391
441
392
- private Document decode (SpELExpressionEvaluator expressionEvaluator , String source , MongoParameterAccessor accessor ,
442
+ private Document decode (Tuple2 < ValueExpressionEvaluator , ParameterBindingDocumentCodec > expressionEvaluator , String source , MongoParameterAccessor accessor ,
393
443
ParameterBindingDocumentCodec codec ) {
394
444
395
445
ParameterBindingContext bindingContext = new ParameterBindingContext (accessor ::getBindableValue ,
396
- expressionEvaluator );
446
+ expressionEvaluator . getT1 () );
397
447
return codec .decode (source , bindingContext );
398
448
}
399
449
@@ -415,17 +465,54 @@ protected Mono<ParameterBindingDocumentCodec> getParameterBindingCodec() {
415
465
* @param accessor must not be {@literal null}.
416
466
* @return a {@link Mono} emitting the {@link SpELExpressionEvaluator} when ready.
417
467
* @since 3.4
468
+ * @deprecated since 4.4.0, use
469
+ * {@link #getValueExpressionEvaluatorLater(ExpressionDependencies, MongoParameterAccessor)} instead
418
470
*/
471
+ @ Deprecated (since = "4.4.0" )
419
472
protected Mono <SpELExpressionEvaluator > getSpelEvaluatorFor (ExpressionDependencies dependencies ,
420
473
MongoParameterAccessor accessor ) {
421
-
422
- return evaluationContextProvider
423
- .getEvaluationContextLater (getQueryMethod ().getParameters (), accessor .getValues (), dependencies )
424
- .map (evaluationContext -> (SpELExpressionEvaluator ) new DefaultSpELExpressionEvaluator (expressionParser ,
425
- evaluationContext ))
474
+ return valueEvaluationContextProvider .getEvaluationContextLater (accessor .getValues (), dependencies )
475
+ .map (evaluationContext -> (SpELExpressionEvaluator ) new DefaultSpELExpressionEvaluator (
476
+ new SpelExpressionParser (), evaluationContext .getEvaluationContext ()))
426
477
.defaultIfEmpty (DefaultSpELExpressionEvaluator .unsupported ());
427
478
}
428
479
480
+ /**
481
+ * Obtain a {@link ValueExpressionEvaluator} suitable to evaluate expressions.
482
+ *
483
+ * @param accessor must not be {@literal null}.
484
+ * @since 4.3
485
+ */
486
+ ValueExpressionEvaluator getValueExpressionEvaluator (MongoParameterAccessor accessor ) {
487
+
488
+ return new ValueExpressionEvaluator () {
489
+
490
+ @ Override
491
+ public <T > T evaluate (String expressionString ) {
492
+ ValueExpression expression = valueExpressionDelegate .parse (expressionString );
493
+ ValueEvaluationContext evaluationContext = valueEvaluationContextProvider .getEvaluationContext (accessor .getValues (),
494
+ expression .getExpressionDependencies ());
495
+ return (T ) expression .evaluate (evaluationContext );
496
+ }
497
+ };
498
+ }
499
+
500
+ /**
501
+ * Obtain a {@link Mono publisher} emitting the {@link ValueExpressionEvaluator} suitable to evaluate expressions
502
+ * backed by the given dependencies.
503
+ *
504
+ * @param dependencies must not be {@literal null}.
505
+ * @param accessor must not be {@literal null}.
506
+ * @return a {@link Mono} emitting the {@link ValueExpressionEvaluator} when ready.
507
+ * @since 4.3
508
+ */
509
+ protected Mono <ValueExpressionEvaluator > getValueExpressionEvaluatorLater (ExpressionDependencies dependencies ,
510
+ MongoParameterAccessor accessor ) {
511
+
512
+ return valueEvaluationContextProvider .getEvaluationContextLater (accessor .getValues (), dependencies )
513
+ .map (evaluationContext -> new ValueExpressionDelegateValueExpressionEvaluator (valueExpressionDelegate , valueExpression -> evaluationContext ));
514
+ }
515
+
429
516
/**
430
517
* @return a {@link Mono} emitting the {@link CodecRegistry} when ready.
431
518
* @since 2.4
0 commit comments