38
38
import org .bson .conversions .Bson ;
39
39
import org .bson .json .JsonReader ;
40
40
import org .bson .types .ObjectId ;
41
-
42
41
import org .springframework .beans .BeansException ;
43
42
import org .springframework .beans .factory .BeanClassLoaderAware ;
44
43
import org .springframework .context .ApplicationContext ;
@@ -187,7 +186,7 @@ protected ConversionContext getConversionContext(ObjectPath path) {
187
186
188
187
Assert .notNull (path , "ObjectPath must not be null" );
189
188
190
- return new ConversionContext (this , conversions , path , this ::readDocument , this ::readCollectionOrArray ,
189
+ return new DefaultConversionContext (this , conversions , path , this ::readDocument , this ::readCollectionOrArray ,
191
190
this ::readMap , this ::readDBRef , this ::getPotentiallyConvertedSimpleRead );
192
191
}
193
192
@@ -396,7 +395,46 @@ private Object doReadOrProject(ConversionContext context, Bson source, TypeInfor
396
395
return readDocument (context , source , typeHint );
397
396
}
398
397
399
- class ProjectingConversionContext extends ConversionContext {
398
+ static class AssociationConversionContext implements ConversionContext {
399
+
400
+ private final ConversionContext delegate ;
401
+
402
+ public AssociationConversionContext (ConversionContext delegate ) {
403
+ this .delegate = delegate ;
404
+ }
405
+
406
+ @ Override
407
+ public <S > S convert (Object source , TypeInformation <? extends S > typeHint , ConversionContext context ) {
408
+ return delegate .convert (source , typeHint , context );
409
+ }
410
+
411
+ @ Override
412
+ public ConversionContext withPath (ObjectPath currentPath ) {
413
+ return new AssociationConversionContext (delegate .withPath (currentPath ));
414
+ }
415
+
416
+ @ Override
417
+ public ObjectPath getPath () {
418
+ return delegate .getPath ();
419
+ }
420
+
421
+ @ Override
422
+ public CustomConversions getCustomConversions () {
423
+ return delegate .getCustomConversions ();
424
+ }
425
+
426
+ @ Override
427
+ public MongoConverter getSourceConverter () {
428
+ return delegate .getSourceConverter ();
429
+ }
430
+
431
+ @ Override
432
+ public boolean resolveIdsInContext () {
433
+ return true ;
434
+ }
435
+ }
436
+
437
+ class ProjectingConversionContext extends DefaultConversionContext {
400
438
401
439
private final EntityProjection <?, ?> returnedTypeDescriptor ;
402
440
@@ -412,20 +450,21 @@ class ProjectingConversionContext extends ConversionContext {
412
450
}
413
451
414
452
@ Override
415
- public ConversionContext forProperty (String name ) {
453
+ public DefaultConversionContext forProperty (String name ) {
416
454
417
455
EntityProjection <?, ?> property = returnedTypeDescriptor .findProperty (name );
418
456
if (property == null ) {
419
- return new ConversionContext (sourceConverter , conversions , path , MappingMongoConverter .this ::readDocument ,
420
- collectionConverter , mapConverter , dbRefConverter , elementConverter );
457
+ return new DefaultConversionContext (sourceConverter , conversions , path ,
458
+ MappingMongoConverter .this ::readDocument , collectionConverter , mapConverter , dbRefConverter ,
459
+ elementConverter );
421
460
}
422
461
423
462
return new ProjectingConversionContext (sourceConverter , conversions , path , collectionConverter , mapConverter ,
424
463
dbRefConverter , elementConverter , property );
425
464
}
426
465
427
466
@ Override
428
- public ConversionContext withPath (ObjectPath currentPath ) {
467
+ public DefaultConversionContext withPath (ObjectPath currentPath ) {
429
468
return new ProjectingConversionContext (sourceConverter , conversions , currentPath , collectionConverter ,
430
469
mapConverter , dbRefConverter , elementConverter , returnedTypeDescriptor );
431
470
}
@@ -544,7 +583,7 @@ private <S> S read(ConversionContext context, MongoPersistentEntity<S> entity, D
544
583
SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator (bson , spELContext );
545
584
DocumentAccessor documentAccessor = new DocumentAccessor (bson );
546
585
547
- if (hasIdentifier (bson )) {
586
+ if (context . resolveIdsInContext () && hasIdentifier (bson )) {
548
587
S existing = findContextualEntity (context , entity , bson );
549
588
if (existing != null ) {
550
589
return existing ;
@@ -647,7 +686,7 @@ private void readProperties(ConversionContext context, MongoPersistentEntity<?>
647
686
continue ;
648
687
}
649
688
650
- ConversionContext propertyContext = context .forProperty (prop . getName () );
689
+ ConversionContext propertyContext = context .forProperty (prop );
651
690
MongoDbPropertyValueProvider valueProviderToUse = valueProvider .withContext (propertyContext );
652
691
653
692
if (prop .isAssociation () && !entity .isConstructorArgument (prop )) {
@@ -721,7 +760,7 @@ private void readAssociation(Association<MongoPersistentProperty> association, P
721
760
accessor .setProperty (property ,
722
761
dbRefResolver .resolveReference (property ,
723
762
new DocumentReferenceSource (documentAccessor .getDocument (), documentAccessor .get (property )),
724
- referenceLookupDelegate , context ::convert ));
763
+ referenceLookupDelegate , context . forProperty ( property ) ::convert ));
725
764
}
726
765
return ;
727
766
}
@@ -1971,13 +2010,13 @@ public <T> T getPropertyValue(MongoPersistentProperty property) {
1971
2010
return null ;
1972
2011
}
1973
2012
1974
- CustomConversions conversions = context .conversions ;
2013
+ CustomConversions conversions = context .getCustomConversions () ;
1975
2014
if (conversions .getPropertyValueConversions ().hasValueConverter (property )) {
1976
2015
return (T ) conversions .getPropertyValueConversions ().getValueConverter (property ).read (value ,
1977
- new MongoConversionContext (property , context .sourceConverter ));
2016
+ new MongoConversionContext (property , context .getSourceConverter () ));
1978
2017
}
1979
2018
1980
- ConversionContext contextToUse = context .forProperty (property . getName () );
2019
+ ConversionContext contextToUse = context .forProperty (property );
1981
2020
1982
2021
return (T ) contextToUse .convert (value , property .getTypeInformation ());
1983
2022
}
@@ -2201,13 +2240,49 @@ public TypeDescriptor toTypeDescriptor() {
2201
2240
}
2202
2241
}
2203
2242
2243
+ interface ConversionContext {
2244
+
2245
+ default <S extends Object > S convert (Object source , TypeInformation <? extends S > typeHint ) {
2246
+ return convert (source , typeHint , this );
2247
+ }
2248
+
2249
+ <S extends Object > S convert (Object source , TypeInformation <? extends S > typeHint , ConversionContext context );
2250
+
2251
+ ConversionContext withPath (ObjectPath currentPath );
2252
+
2253
+ ObjectPath getPath ();
2254
+
2255
+ default ConversionContext forProperty (String name ) {
2256
+ return this ;
2257
+ }
2258
+
2259
+ default ConversionContext forProperty (@ Nullable PersistentProperty property ) {
2260
+
2261
+ if (property != null ) {
2262
+ if (property .isAssociation ()) {
2263
+ return new AssociationConversionContext (forProperty (property .getName ()));
2264
+ }
2265
+ return forProperty (property .getName ());
2266
+ }
2267
+ return this ;
2268
+ }
2269
+
2270
+ default boolean resolveIdsInContext () {
2271
+ return false ;
2272
+ }
2273
+
2274
+ CustomConversions getCustomConversions ();
2275
+
2276
+ MongoConverter getSourceConverter ();
2277
+ }
2278
+
2204
2279
/**
2205
2280
* Conversion context holding references to simple {@link ValueConverter} and {@link ContainerValueConverter}.
2206
2281
* Entrypoint for recursive conversion of {@link Document} and other types.
2207
2282
*
2208
2283
* @since 3.2
2209
2284
*/
2210
- protected static class ConversionContext {
2285
+ protected static class DefaultConversionContext implements ConversionContext {
2211
2286
2212
2287
final MongoConverter sourceConverter ;
2213
2288
final org .springframework .data .convert .CustomConversions conversions ;
@@ -2218,7 +2293,7 @@ protected static class ConversionContext {
2218
2293
final ContainerValueConverter <DBRef > dbRefConverter ;
2219
2294
final ValueConverter <Object > elementConverter ;
2220
2295
2221
- ConversionContext (MongoConverter sourceConverter ,
2296
+ DefaultConversionContext (MongoConverter sourceConverter ,
2222
2297
org .springframework .data .convert .CustomConversions customConversions , ObjectPath path ,
2223
2298
ContainerValueConverter <Bson > documentConverter , ContainerValueConverter <Collection <?>> collectionConverter ,
2224
2299
ContainerValueConverter <Bson > mapConverter , ContainerValueConverter <DBRef > dbRefConverter ,
@@ -2242,7 +2317,8 @@ protected static class ConversionContext {
2242
2317
* @return the converted object.
2243
2318
*/
2244
2319
@ SuppressWarnings ("unchecked" )
2245
- public <S extends Object > S convert (Object source , TypeInformation <? extends S > typeHint ) {
2320
+ public <S extends Object > S convert (Object source , TypeInformation <? extends S > typeHint ,
2321
+ ConversionContext context ) {
2246
2322
2247
2323
Assert .notNull (source , "Source must not be null" );
2248
2324
Assert .notNull (typeHint , "TypeInformation must not be null" );
@@ -2262,26 +2338,26 @@ public <S extends Object> S convert(Object source, TypeInformation<? extends S>
2262
2338
}
2263
2339
2264
2340
if (typeHint .isCollectionLike () || typeHint .getType ().isAssignableFrom (Collection .class )) {
2265
- return (S ) collectionConverter .convert (this , (Collection <?>) source , typeHint );
2341
+ return (S ) collectionConverter .convert (context , (Collection <?>) source , typeHint );
2266
2342
}
2267
2343
}
2268
2344
2269
2345
if (typeHint .isMap ()) {
2270
2346
2271
2347
if (ClassUtils .isAssignable (Document .class , typeHint .getType ())) {
2272
- return (S ) documentConverter .convert (this , BsonUtils .asBson (source ), typeHint );
2348
+ return (S ) documentConverter .convert (context , BsonUtils .asBson (source ), typeHint );
2273
2349
}
2274
2350
2275
2351
if (BsonUtils .supportsBson (source )) {
2276
- return (S ) mapConverter .convert (this , BsonUtils .asBson (source ), typeHint );
2352
+ return (S ) mapConverter .convert (context , BsonUtils .asBson (source ), typeHint );
2277
2353
}
2278
2354
2279
2355
throw new IllegalArgumentException (
2280
2356
String .format ("Expected map like structure but found %s" , source .getClass ()));
2281
2357
}
2282
2358
2283
2359
if (source instanceof DBRef ) {
2284
- return (S ) dbRefConverter .convert (this , (DBRef ) source , typeHint );
2360
+ return (S ) dbRefConverter .convert (context , (DBRef ) source , typeHint );
2285
2361
}
2286
2362
2287
2363
if (source instanceof Collection ) {
@@ -2290,31 +2366,41 @@ public <S extends Object> S convert(Object source, TypeInformation<? extends S>
2290
2366
}
2291
2367
2292
2368
if (BsonUtils .supportsBson (source )) {
2293
- return (S ) documentConverter .convert (this , BsonUtils .asBson (source ), typeHint );
2369
+ return (S ) documentConverter .convert (context , BsonUtils .asBson (source ), typeHint );
2294
2370
}
2295
2371
2296
2372
return (S ) elementConverter .convert (source , typeHint );
2297
2373
}
2298
2374
2375
+ @ Override
2376
+ public CustomConversions getCustomConversions () {
2377
+ return conversions ;
2378
+ }
2379
+
2380
+ @ Override
2381
+ public MongoConverter getSourceConverter () {
2382
+ return sourceConverter ;
2383
+ }
2384
+
2299
2385
/**
2300
- * Create a new {@link ConversionContext } with {@link ObjectPath currentPath} applied.
2386
+ * Create a new {@link DefaultConversionContext } with {@link ObjectPath currentPath} applied.
2301
2387
*
2302
2388
* @param currentPath must not be {@literal null}.
2303
- * @return a new {@link ConversionContext } with {@link ObjectPath currentPath} applied.
2389
+ * @return a new {@link DefaultConversionContext } with {@link ObjectPath currentPath} applied.
2304
2390
*/
2305
- public ConversionContext withPath (ObjectPath currentPath ) {
2391
+ public DefaultConversionContext withPath (ObjectPath currentPath ) {
2306
2392
2307
2393
Assert .notNull (currentPath , "ObjectPath must not be null" );
2308
2394
2309
- return new ConversionContext (sourceConverter , conversions , currentPath , documentConverter , collectionConverter ,
2310
- mapConverter , dbRefConverter , elementConverter );
2395
+ return new DefaultConversionContext (sourceConverter , conversions , currentPath , documentConverter ,
2396
+ collectionConverter , mapConverter , dbRefConverter , elementConverter );
2311
2397
}
2312
2398
2313
2399
public ObjectPath getPath () {
2314
2400
return path ;
2315
2401
}
2316
2402
2317
- public ConversionContext forProperty (String name ) {
2403
+ public DefaultConversionContext forProperty (String name ) {
2318
2404
return this ;
2319
2405
}
2320
2406
0 commit comments