26
26
import org .bson .BsonNull ;
27
27
import org .bson .Document ;
28
28
import org .springframework .core .convert .ConversionService ;
29
+ import org .springframework .core .env .Environment ;
30
+ import org .springframework .core .env .EnvironmentCapable ;
29
31
import org .springframework .dao .InvalidDataAccessApiUsageException ;
30
32
import org .springframework .data .convert .CustomConversions ;
33
+ import org .springframework .data .expression .ValueEvaluationContext ;
31
34
import org .springframework .data .mapping .IdentifierAccessor ;
32
35
import org .springframework .data .mapping .MappingException ;
33
36
import org .springframework .data .mapping .PersistentEntity ;
41
44
import org .springframework .data .mongodb .core .convert .MongoJsonSchemaMapper ;
42
45
import org .springframework .data .mongodb .core .convert .MongoWriter ;
43
46
import org .springframework .data .mongodb .core .convert .QueryMapper ;
47
+ import org .springframework .data .mongodb .core .mapping .BasicMongoPersistentEntity ;
44
48
import org .springframework .data .mongodb .core .mapping .FieldName ;
45
- import org .springframework .data .mongodb .core .index .DurationStyle ;
46
- import org .springframework .data .mongodb .core .mapping .*;
49
+ import org .springframework .data .mongodb .core .mapping .MongoPersistentEntity ;
50
+ import org .springframework .data .mongodb .core .mapping .MongoPersistentProperty ;
51
+ import org .springframework .data .mongodb .core .mapping .MongoSimpleTypes ;
52
+ import org .springframework .data .mongodb .core .mapping .TimeSeries ;
47
53
import org .springframework .data .mongodb .core .query .Collation ;
48
54
import org .springframework .data .mongodb .core .query .Criteria ;
49
55
import org .springframework .data .mongodb .core .query .Query ;
50
56
import org .springframework .data .mongodb .core .timeseries .Granularity ;
51
57
import org .springframework .data .mongodb .core .validation .Validator ;
52
58
import org .springframework .data .mongodb .util .BsonUtils ;
59
+ import org .springframework .data .mongodb .util .DurationUtil ;
53
60
import org .springframework .data .projection .EntityProjection ;
54
61
import org .springframework .data .projection .EntityProjectionIntrospector ;
55
62
import org .springframework .data .projection .ProjectionFactory ;
56
63
import org .springframework .data .projection .TargetAware ;
57
- import org .springframework .data .spel .EvaluationContextProvider ;
58
64
import org .springframework .data .util .Optionals ;
59
- import org .springframework .expression .EvaluationContext ;
60
- import org .springframework .expression .Expression ;
61
- import org .springframework .expression .ParserContext ;
62
- import org .springframework .expression .common .LiteralExpression ;
63
- import org .springframework .expression .spel .standard .SpelExpressionParser ;
65
+ import org .springframework .expression .spel .support .SimpleEvaluationContext ;
64
66
import org .springframework .lang .Nullable ;
65
67
import org .springframework .util .Assert ;
66
68
import org .springframework .util .ClassUtils ;
@@ -96,7 +98,7 @@ class EntityOperations {
96
98
97
99
private final MongoJsonSchemaMapper schemaMapper ;
98
100
99
- private EvaluationContextProvider evaluationContextProvider = EvaluationContextProvider . DEFAULT ;
101
+ private @ Nullable Environment environment ;
100
102
101
103
EntityOperations (MongoConverter converter ) {
102
104
this (converter , new QueryMapper (converter ));
@@ -117,6 +119,9 @@ class EntityOperations {
117
119
.and (((target , underlyingType ) -> !conversions .isSimpleType (target ))),
118
120
context );
119
121
this .schemaMapper = new MongoJsonSchemaMapper (converter );
122
+ if (converter instanceof EnvironmentCapable environmentCapable ) {
123
+ this .environment = environmentCapable .getEnvironment ();
124
+ }
120
125
}
121
126
122
127
/**
@@ -285,7 +290,7 @@ public <T> TypedOperations<T> forType(@Nullable Class<T> entityClass) {
285
290
MongoPersistentEntity <?> entity = context .getPersistentEntity (entityClass );
286
291
287
292
if (entity != null ) {
288
- return new TypedEntityOperations (entity , evaluationContextProvider );
293
+ return new TypedEntityOperations (entity , environment );
289
294
}
290
295
291
296
}
@@ -363,8 +368,8 @@ public CreateCollectionOptions convertToCreateCollectionOptions(@Nullable Collec
363
368
options .granularity (TimeSeriesGranularity .valueOf (it .getGranularity ().name ().toUpperCase ()));
364
369
}
365
370
366
- if (it .getExpireAfterSeconds () >= 0 ) {
367
- result .expireAfter (it .getExpireAfterSeconds (), TimeUnit .SECONDS );
371
+ if (! it .getExpireAfter (). isNegative () ) {
372
+ result .expireAfter (it .getExpireAfter (). toSeconds (), TimeUnit .SECONDS );
368
373
}
369
374
370
375
result .timeSeriesOptions (options );
@@ -1039,13 +1044,14 @@ public TimeSeriesOptions mapTimeSeriesOptions(TimeSeriesOptions options) {
1039
1044
*/
1040
1045
static class TypedEntityOperations <T > implements TypedOperations <T > {
1041
1046
1042
- private static final SpelExpressionParser PARSER = new SpelExpressionParser ();
1043
1047
private final MongoPersistentEntity <T > entity ;
1044
- private final EvaluationContextProvider evaluationContextProvider ;
1045
1048
1046
- protected TypedEntityOperations (MongoPersistentEntity <T > entity , EvaluationContextProvider evaluationContextProvider ) {
1049
+ @ Nullable private final Environment environment ;
1050
+
1051
+ protected TypedEntityOperations (MongoPersistentEntity <T > entity , @ Nullable Environment environment ) {
1052
+
1047
1053
this .entity = entity ;
1048
- this .evaluationContextProvider = evaluationContextProvider ;
1054
+ this .environment = environment ;
1049
1055
}
1050
1056
1051
1057
@ Override
@@ -1094,21 +1100,10 @@ public CollectionOptions getCollectionOptions() {
1094
1100
options = options .granularity (timeSeries .granularity ());
1095
1101
}
1096
1102
1097
- if (timeSeries .expireAfterSeconds () >= 0 ) {
1098
- options = options .expireAfter (Duration .ofSeconds (timeSeries .expireAfterSeconds ()));
1099
- }
1100
-
1101
1103
if (StringUtils .hasText (timeSeries .expireAfter ())) {
1102
1104
1103
- if (timeSeries .expireAfterSeconds () >= 0 ) {
1104
- throw new IllegalStateException (String .format (
1105
- "@TimeSeries already defines an expiration timeout of %s seconds via TimeSeries#expireAfterSeconds; Please make to use either expireAfterSeconds or expireAfter" ,
1106
- timeSeries .expireAfterSeconds ()));
1107
- }
1108
-
1109
- Duration timeout = computeIndexTimeout (timeSeries .expireAfter (),
1110
- getEvaluationContextForProperty (entity ));
1111
- if (!timeout .isZero () && !timeout .isNegative ()) {
1105
+ Duration timeout = computeIndexTimeout (timeSeries .expireAfter (), getEvaluationContextForEntity (entity ));
1106
+ if (!timeout .isNegative ()) {
1112
1107
options = options .expireAfter (timeout );
1113
1108
}
1114
1109
}
@@ -1127,105 +1122,45 @@ public TimeSeriesOptions mapTimeSeriesOptions(TimeSeriesOptions source) {
1127
1122
if (StringUtils .hasText (source .getMetaField ())) {
1128
1123
target = target .metaField (mappedNameOrDefault (source .getMetaField ()));
1129
1124
}
1130
- return target .granularity (source .getGranularity ())
1131
- .expireAfter (Duration .ofSeconds (source .getExpireAfterSeconds ()));
1132
- }
1133
-
1134
- private String mappedNameOrDefault (String name ) {
1135
- MongoPersistentProperty persistentProperty = entity .getPersistentProperty (name );
1136
- return persistentProperty != null ? persistentProperty .getFieldName () : name ;
1125
+ return target .granularity (source .getGranularity ()).expireAfter (source .getExpireAfter ());
1137
1126
}
1138
1127
1139
1128
@ Override
1140
1129
public String getIdKeyName () {
1141
1130
return entity .getIdProperty ().getName ();
1142
1131
}
1143
- }
1144
-
1145
-
1146
- /**
1147
- * Compute the index timeout value by evaluating a potential
1148
- * {@link org.springframework.expression.spel.standard.SpelExpression} and parsing the final value.
1149
- *
1150
- * @param timeoutValue must not be {@literal null}.
1151
- * @param evaluationContext must not be {@literal null}.
1152
- * @return never {@literal null}
1153
- * @since 2.2
1154
- * @throws IllegalArgumentException for invalid duration values.
1155
- */
1156
- private static Duration computeIndexTimeout (String timeoutValue , EvaluationContext evaluationContext ) {
1157
-
1158
- Object evaluatedTimeout = evaluate (timeoutValue , evaluationContext );
1159
-
1160
- if (evaluatedTimeout == null ) {
1161
- return Duration .ZERO ;
1162
- }
1163
1132
1164
- if (evaluatedTimeout instanceof Duration ) {
1165
- return (Duration ) evaluatedTimeout ;
1166
- }
1167
-
1168
- String val = evaluatedTimeout .toString ();
1169
-
1170
- if (val == null ) {
1171
- return Duration .ZERO ;
1172
- }
1173
-
1174
- return DurationStyle .detectAndParse (val );
1175
- }
1176
-
1177
- @ Nullable
1178
- private static Object evaluate (String value , EvaluationContext evaluationContext ) {
1179
-
1180
- Expression expression = PARSER .parseExpression (value , ParserContext .TEMPLATE_EXPRESSION );
1181
- if (expression instanceof LiteralExpression ) {
1182
- return value ;
1183
- }
1184
-
1185
- return expression .getValue (evaluationContext , Object .class );
1133
+ private String mappedNameOrDefault (String name ) {
1134
+ MongoPersistentProperty persistentProperty = entity .getPersistentProperty (name );
1135
+ return persistentProperty != null ? persistentProperty .getFieldName () : name ;
1186
1136
}
1187
1137
1188
-
1189
1138
/**
1190
- * Get the {@link EvaluationContext } for a given {@link PersistentEntity entity} the default one.
1139
+ * Get the {@link ValueEvaluationContext } for a given {@link PersistentEntity entity} the default one.
1191
1140
*
1192
1141
* @param persistentEntity can be {@literal null}
1193
- * @return
1142
+ * @return the context to use.
1194
1143
*/
1195
- private EvaluationContext getEvaluationContextForProperty (@ Nullable PersistentEntity <?, ?> persistentEntity ) {
1144
+ private ValueEvaluationContext getEvaluationContextForEntity (@ Nullable PersistentEntity <?, ?> persistentEntity ) {
1196
1145
1197
- if (!( persistentEntity instanceof BasicMongoPersistentEntity ) ) {
1198
- return getEvaluationContext ( );
1146
+ if (persistentEntity instanceof BasicMongoPersistentEntity <?> mongoEntity ) {
1147
+ return mongoEntity . getValueEvaluationContext ( null );
1199
1148
}
1200
1149
1201
- EvaluationContext contextFromEntity = ((BasicMongoPersistentEntity <?>) persistentEntity ).getEvaluationContext (null );
1202
-
1203
- if (!EvaluationContextProvider .DEFAULT .equals (contextFromEntity )) {
1204
- return contextFromEntity ;
1205
- }
1206
-
1207
- return getEvaluationContext ();
1150
+ return ValueEvaluationContext .of (this .environment , SimpleEvaluationContext .forReadOnlyDataBinding ().build ());
1208
1151
}
1209
1152
1210
1153
/**
1211
- * Get the default {@link EvaluationContext}.
1154
+ * Compute the index timeout value by evaluating a potential
1155
+ * {@link org.springframework.expression.spel.standard.SpelExpression} and parsing the final value.
1212
1156
*
1213
- * @return never {@literal null}.
1214
- * @since 2.2
1157
+ * @param timeoutValue must not be {@literal null}.
1158
+ * @param evaluationContext must not be {@literal null}.
1159
+ * @return never {@literal null}
1160
+ * @throws IllegalArgumentException for invalid duration values.
1215
1161
*/
1216
- protected EvaluationContext getEvaluationContext ( ) {
1217
- return evaluationContextProvider . getEvaluationContext ( null );
1162
+ private static Duration computeIndexTimeout ( String timeoutValue , ValueEvaluationContext evaluationContext ) {
1163
+ return DurationUtil . evaluate ( timeoutValue , evaluationContext );
1218
1164
}
1219
1165
}
1220
-
1221
- /**
1222
- * Set the {@link EvaluationContextProvider} used for obtaining the {@link EvaluationContext} used to compute
1223
- * {@link org.springframework.expression.spel.standard.SpelExpression expressions}.
1224
- *
1225
- * @param evaluationContextProvider must not be {@literal null}.
1226
- * @since 2.2
1227
- */
1228
- public void setEvaluationContextProvider (EvaluationContextProvider evaluationContextProvider ) {
1229
- this .evaluationContextProvider = evaluationContextProvider ;
1230
- }
1231
1166
}
0 commit comments