39
39
import org .bson .conversions .Bson ;
40
40
import org .bson .json .JsonReader ;
41
41
import org .bson .types .ObjectId ;
42
-
43
42
import org .springframework .beans .BeansException ;
44
43
import org .springframework .beans .factory .BeanClassLoaderAware ;
45
44
import org .springframework .context .ApplicationContext ;
@@ -188,7 +187,7 @@ protected ConversionContext getConversionContext(ObjectPath path) {
188
187
189
188
Assert .notNull (path , "ObjectPath must not be null" );
190
189
191
- return new ConversionContext (this , conversions , path , this ::readDocument , this ::readCollectionOrArray ,
190
+ return new DefaultConversionContext (this , conversions , path , this ::readDocument , this ::readCollectionOrArray ,
192
191
this ::readMap , this ::readDBRef , this ::getPotentiallyConvertedSimpleRead );
193
192
}
194
193
@@ -385,7 +384,46 @@ private Object doReadOrProject(ConversionContext context, Bson source, TypeInfor
385
384
return readDocument (context , source , typeHint );
386
385
}
387
386
388
- class ProjectingConversionContext extends ConversionContext {
387
+ static class AssociationConversionContext implements ConversionContext {
388
+
389
+ private final ConversionContext delegate ;
390
+
391
+ public AssociationConversionContext (ConversionContext delegate ) {
392
+ this .delegate = delegate ;
393
+ }
394
+
395
+ @ Override
396
+ public <S > S convert (Object source , TypeInformation <? extends S > typeHint , ConversionContext context ) {
397
+ return delegate .convert (source , typeHint , context );
398
+ }
399
+
400
+ @ Override
401
+ public ConversionContext withPath (ObjectPath currentPath ) {
402
+ return new AssociationConversionContext (delegate .withPath (currentPath ));
403
+ }
404
+
405
+ @ Override
406
+ public ObjectPath getPath () {
407
+ return delegate .getPath ();
408
+ }
409
+
410
+ @ Override
411
+ public CustomConversions getCustomConversions () {
412
+ return delegate .getCustomConversions ();
413
+ }
414
+
415
+ @ Override
416
+ public MongoConverter getSourceConverter () {
417
+ return delegate .getSourceConverter ();
418
+ }
419
+
420
+ @ Override
421
+ public boolean resolveIdsInContext () {
422
+ return true ;
423
+ }
424
+ }
425
+
426
+ class ProjectingConversionContext extends DefaultConversionContext {
389
427
390
428
private final EntityProjection <?, ?> returnedTypeDescriptor ;
391
429
@@ -401,20 +439,21 @@ class ProjectingConversionContext extends ConversionContext {
401
439
}
402
440
403
441
@ Override
404
- public ConversionContext forProperty (String name ) {
442
+ public DefaultConversionContext forProperty (String name ) {
405
443
406
444
EntityProjection <?, ?> property = returnedTypeDescriptor .findProperty (name );
407
445
if (property == null ) {
408
- return new ConversionContext (sourceConverter , conversions , path , MappingMongoConverter .this ::readDocument ,
409
- collectionConverter , mapConverter , dbRefConverter , elementConverter );
446
+ return new DefaultConversionContext (sourceConverter , conversions , path ,
447
+ MappingMongoConverter .this ::readDocument , collectionConverter , mapConverter , dbRefConverter ,
448
+ elementConverter );
410
449
}
411
450
412
451
return new ProjectingConversionContext (sourceConverter , conversions , path , collectionConverter , mapConverter ,
413
452
dbRefConverter , elementConverter , property );
414
453
}
415
454
416
455
@ Override
417
- public ConversionContext withPath (ObjectPath currentPath ) {
456
+ public DefaultConversionContext withPath (ObjectPath currentPath ) {
418
457
return new ProjectingConversionContext (sourceConverter , conversions , currentPath , collectionConverter ,
419
458
mapConverter , dbRefConverter , elementConverter , returnedTypeDescriptor );
420
459
}
@@ -529,7 +568,7 @@ private <S> S read(ConversionContext context, MongoPersistentEntity<S> entity, D
529
568
SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator (bson , spELContext );
530
569
DocumentAccessor documentAccessor = new DocumentAccessor (bson );
531
570
532
- if (hasIdentifier (bson )) {
571
+ if (context . resolveIdsInContext () && hasIdentifier (bson )) {
533
572
S existing = findContextualEntity (context , entity , bson );
534
573
if (existing != null ) {
535
574
return existing ;
@@ -632,7 +671,7 @@ private void readProperties(ConversionContext context, MongoPersistentEntity<?>
632
671
continue ;
633
672
}
634
673
635
- ConversionContext propertyContext = context .forProperty (prop . getName () );
674
+ ConversionContext propertyContext = context .forProperty (prop );
636
675
MongoDbPropertyValueProvider valueProviderToUse = valueProvider .withContext (propertyContext );
637
676
638
677
if (prop .isAssociation () && !entity .isConstructorArgument (prop )) {
@@ -706,7 +745,7 @@ private void readAssociation(Association<MongoPersistentProperty> association, P
706
745
accessor .setProperty (property ,
707
746
dbRefResolver .resolveReference (property ,
708
747
new DocumentReferenceSource (documentAccessor .getDocument (), documentAccessor .get (property )),
709
- referenceLookupDelegate , context ::convert ));
748
+ referenceLookupDelegate , context . forProperty ( property ) ::convert ));
710
749
}
711
750
return ;
712
751
}
@@ -1935,13 +1974,13 @@ public <T> T getPropertyValue(MongoPersistentProperty property) {
1935
1974
return null ;
1936
1975
}
1937
1976
1938
- CustomConversions conversions = context .conversions ;
1977
+ CustomConversions conversions = context .getCustomConversions () ;
1939
1978
if (conversions .hasValueConverter (property )) {
1940
1979
return (T ) conversions .getPropertyValueConversions ().getValueConverter (property ).read (value ,
1941
- new MongoConversionContext (property , context .sourceConverter ));
1980
+ new MongoConversionContext (property , context .getSourceConverter () ));
1942
1981
}
1943
1982
1944
- ConversionContext contextToUse = context .forProperty (property . getName () );
1983
+ ConversionContext contextToUse = context .forProperty (property );
1945
1984
1946
1985
return (T ) contextToUse .convert (value , property .getTypeInformation ());
1947
1986
}
@@ -2158,13 +2197,49 @@ public TypeDescriptor toTypeDescriptor() {
2158
2197
}
2159
2198
}
2160
2199
2200
+ interface ConversionContext {
2201
+
2202
+ default <S extends Object > S convert (Object source , TypeInformation <? extends S > typeHint ) {
2203
+ return convert (source , typeHint , this );
2204
+ }
2205
+
2206
+ <S extends Object > S convert (Object source , TypeInformation <? extends S > typeHint , ConversionContext context );
2207
+
2208
+ ConversionContext withPath (ObjectPath currentPath );
2209
+
2210
+ ObjectPath getPath ();
2211
+
2212
+ default ConversionContext forProperty (String name ) {
2213
+ return this ;
2214
+ }
2215
+
2216
+ default ConversionContext forProperty (@ Nullable PersistentProperty property ) {
2217
+
2218
+ if (property != null ) {
2219
+ if (property .isAssociation ()) {
2220
+ return new AssociationConversionContext (forProperty (property .getName ()));
2221
+ }
2222
+ return forProperty (property .getName ());
2223
+ }
2224
+ return this ;
2225
+ }
2226
+
2227
+ default boolean resolveIdsInContext () {
2228
+ return false ;
2229
+ }
2230
+
2231
+ CustomConversions getCustomConversions ();
2232
+
2233
+ MongoConverter getSourceConverter ();
2234
+ }
2235
+
2161
2236
/**
2162
2237
* Conversion context holding references to simple {@link ValueConverter} and {@link ContainerValueConverter}.
2163
2238
* Entrypoint for recursive conversion of {@link Document} and other types.
2164
2239
*
2165
2240
* @since 3.2
2166
2241
*/
2167
- protected static class ConversionContext {
2242
+ protected static class DefaultConversionContext implements ConversionContext {
2168
2243
2169
2244
final MongoConverter sourceConverter ;
2170
2245
final org .springframework .data .convert .CustomConversions conversions ;
@@ -2175,7 +2250,7 @@ protected static class ConversionContext {
2175
2250
final ContainerValueConverter <DBRef > dbRefConverter ;
2176
2251
final ValueConverter <Object > elementConverter ;
2177
2252
2178
- ConversionContext (MongoConverter sourceConverter ,
2253
+ DefaultConversionContext (MongoConverter sourceConverter ,
2179
2254
org .springframework .data .convert .CustomConversions customConversions , ObjectPath path ,
2180
2255
ContainerValueConverter <Bson > documentConverter , ContainerValueConverter <Collection <?>> collectionConverter ,
2181
2256
ContainerValueConverter <Bson > mapConverter , ContainerValueConverter <DBRef > dbRefConverter ,
@@ -2199,7 +2274,8 @@ protected static class ConversionContext {
2199
2274
* @return the converted object.
2200
2275
*/
2201
2276
@ SuppressWarnings ("unchecked" )
2202
- public <S extends Object > S convert (Object source , TypeInformation <? extends S > typeHint ) {
2277
+ public <S extends Object > S convert (Object source , TypeInformation <? extends S > typeHint ,
2278
+ ConversionContext context ) {
2203
2279
2204
2280
Assert .notNull (source , "Source must not be null" );
2205
2281
Assert .notNull (typeHint , "TypeInformation must not be null" );
@@ -2219,26 +2295,26 @@ public <S extends Object> S convert(Object source, TypeInformation<? extends S>
2219
2295
}
2220
2296
2221
2297
if (typeHint .isCollectionLike () || typeHint .getType ().isAssignableFrom (Collection .class )) {
2222
- return (S ) collectionConverter .convert (this , (Collection <?>) source , typeHint );
2298
+ return (S ) collectionConverter .convert (context , (Collection <?>) source , typeHint );
2223
2299
}
2224
2300
}
2225
2301
2226
2302
if (typeHint .isMap ()) {
2227
2303
2228
2304
if (ClassUtils .isAssignable (Document .class , typeHint .getType ())) {
2229
- return (S ) documentConverter .convert (this , BsonUtils .asBson (source ), typeHint );
2305
+ return (S ) documentConverter .convert (context , BsonUtils .asBson (source ), typeHint );
2230
2306
}
2231
2307
2232
2308
if (BsonUtils .supportsBson (source )) {
2233
- return (S ) mapConverter .convert (this , BsonUtils .asBson (source ), typeHint );
2309
+ return (S ) mapConverter .convert (context , BsonUtils .asBson (source ), typeHint );
2234
2310
}
2235
2311
2236
2312
throw new IllegalArgumentException (
2237
2313
String .format ("Expected map like structure but found %s" , source .getClass ()));
2238
2314
}
2239
2315
2240
2316
if (source instanceof DBRef ) {
2241
- return (S ) dbRefConverter .convert (this , (DBRef ) source , typeHint );
2317
+ return (S ) dbRefConverter .convert (context , (DBRef ) source , typeHint );
2242
2318
}
2243
2319
2244
2320
if (source instanceof Collection ) {
@@ -2247,31 +2323,41 @@ public <S extends Object> S convert(Object source, TypeInformation<? extends S>
2247
2323
}
2248
2324
2249
2325
if (BsonUtils .supportsBson (source )) {
2250
- return (S ) documentConverter .convert (this , BsonUtils .asBson (source ), typeHint );
2326
+ return (S ) documentConverter .convert (context , BsonUtils .asBson (source ), typeHint );
2251
2327
}
2252
2328
2253
2329
return (S ) elementConverter .convert (source , typeHint );
2254
2330
}
2255
2331
2332
+ @ Override
2333
+ public CustomConversions getCustomConversions () {
2334
+ return conversions ;
2335
+ }
2336
+
2337
+ @ Override
2338
+ public MongoConverter getSourceConverter () {
2339
+ return sourceConverter ;
2340
+ }
2341
+
2256
2342
/**
2257
- * Create a new {@link ConversionContext } with {@link ObjectPath currentPath} applied.
2343
+ * Create a new {@link DefaultConversionContext } with {@link ObjectPath currentPath} applied.
2258
2344
*
2259
2345
* @param currentPath must not be {@literal null}.
2260
- * @return a new {@link ConversionContext } with {@link ObjectPath currentPath} applied.
2346
+ * @return a new {@link DefaultConversionContext } with {@link ObjectPath currentPath} applied.
2261
2347
*/
2262
- public ConversionContext withPath (ObjectPath currentPath ) {
2348
+ public DefaultConversionContext withPath (ObjectPath currentPath ) {
2263
2349
2264
2350
Assert .notNull (currentPath , "ObjectPath must not be null" );
2265
2351
2266
- return new ConversionContext (sourceConverter , conversions , currentPath , documentConverter , collectionConverter ,
2267
- mapConverter , dbRefConverter , elementConverter );
2352
+ return new DefaultConversionContext (sourceConverter , conversions , currentPath , documentConverter ,
2353
+ collectionConverter , mapConverter , dbRefConverter , elementConverter );
2268
2354
}
2269
2355
2270
2356
public ObjectPath getPath () {
2271
2357
return path ;
2272
2358
}
2273
2359
2274
- public ConversionContext forProperty (String name ) {
2360
+ public DefaultConversionContext forProperty (String name ) {
2275
2361
return this ;
2276
2362
}
2277
2363
0 commit comments