Skip to content

Commit dfa1822

Browse files
committed
Polishing.
Encapsulate nested object lookup. Refine method signatures and tweak Javadoc. See #4098 Original pull request: #4133.
1 parent 48aabfb commit dfa1822

File tree

1 file changed

+150
-122
lines changed

1 file changed

+150
-122
lines changed

Diff for: spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java

+150-122
Original file line numberDiff line numberDiff line change
@@ -395,81 +395,6 @@ private Object doReadOrProject(ConversionContext context, Bson source, TypeInfor
395395
return readDocument(context, source, typeHint);
396396
}
397397

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 {
438-
439-
private final EntityProjection<?, ?> returnedTypeDescriptor;
440-
441-
ProjectingConversionContext(MongoConverter sourceConverter, CustomConversions customConversions, ObjectPath path,
442-
ContainerValueConverter<Collection<?>> collectionConverter, ContainerValueConverter<Bson> mapConverter,
443-
ContainerValueConverter<DBRef> dbRefConverter, ValueConverter<Object> elementConverter,
444-
EntityProjection<?, ?> projection) {
445-
super(sourceConverter, customConversions, path,
446-
(context, source, typeHint) -> doReadOrProject(context, source, typeHint, projection),
447-
448-
collectionConverter, mapConverter, dbRefConverter, elementConverter);
449-
this.returnedTypeDescriptor = projection;
450-
}
451-
452-
@Override
453-
public DefaultConversionContext forProperty(String name) {
454-
455-
EntityProjection<?, ?> property = returnedTypeDescriptor.findProperty(name);
456-
if (property == null) {
457-
return new DefaultConversionContext(sourceConverter, conversions, path,
458-
MappingMongoConverter.this::readDocument, collectionConverter, mapConverter, dbRefConverter,
459-
elementConverter);
460-
}
461-
462-
return new ProjectingConversionContext(sourceConverter, conversions, path, collectionConverter, mapConverter,
463-
dbRefConverter, elementConverter, property);
464-
}
465-
466-
@Override
467-
public DefaultConversionContext withPath(ObjectPath currentPath) {
468-
return new ProjectingConversionContext(sourceConverter, conversions, currentPath, collectionConverter,
469-
mapConverter, dbRefConverter, elementConverter, returnedTypeDescriptor);
470-
}
471-
}
472-
473398
static class MapPersistentPropertyAccessor implements PersistentPropertyAccessor<Map<String, Object>> {
474399

475400
Map<String, Object> map = new LinkedHashMap<>();
@@ -580,16 +505,14 @@ private ParameterValueProvider<MongoPersistentProperty> getParameterProvider(Con
580505

581506
private <S> S read(ConversionContext context, MongoPersistentEntity<S> entity, Document bson) {
582507

508+
S existing = context.findContextualEntity(entity, bson);
509+
if (existing != null) {
510+
return existing;
511+
}
512+
583513
SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(bson, spELContext);
584514
DocumentAccessor documentAccessor = new DocumentAccessor(bson);
585515

586-
if (context.resolveIdsInContext() && hasIdentifier(bson)) {
587-
S existing = findContextualEntity(context, entity, bson);
588-
if (existing != null) {
589-
return existing;
590-
}
591-
}
592-
593516
PreferredConstructor<S, MongoPersistentProperty> persistenceConstructor = entity.getPersistenceConstructor();
594517

595518
ParameterValueProvider<MongoPersistentProperty> provider = persistenceConstructor != null
@@ -607,16 +530,6 @@ private <S> S read(ConversionContext context, MongoPersistentEntity<S> entity, D
607530
return instance;
608531
}
609532

610-
private boolean hasIdentifier(Document bson) {
611-
return bson.get(BasicMongoPersistentProperty.ID_FIELD_NAME) != null;
612-
}
613-
614-
@Nullable
615-
private <S> S findContextualEntity(ConversionContext context, MongoPersistentEntity<S> entity, Document bson) {
616-
return context.getPath().getPathItem(bson.get(BasicMongoPersistentProperty.ID_FIELD_NAME), entity.getCollection(),
617-
entity.getType());
618-
}
619-
620533
private <S> S populateProperties(ConversionContext context, MongoPersistentEntity<S> entity,
621534
DocumentAccessor documentAccessor, SpELExpressionEvaluator evaluator, S instance) {
622535

@@ -2240,40 +2153,130 @@ public TypeDescriptor toTypeDescriptor() {
22402153
}
22412154
}
22422155

2156+
/**
2157+
* Conversion context defining an interface for graph-traversal-based conversion of documents. Entrypoint for
2158+
* recursive conversion of {@link Document} and other types.
2159+
*
2160+
* @since 3.4.3
2161+
*/
22432162
interface ConversionContext {
22442163

2164+
/**
2165+
* Converts a source object into {@link TypeInformation target}.
2166+
*
2167+
* @param source must not be {@literal null}.
2168+
* @param typeHint must not be {@literal null}.
2169+
* @return the converted object.
2170+
*/
22452171
default <S extends Object> S convert(Object source, TypeInformation<? extends S> typeHint) {
22462172
return convert(source, typeHint, this);
22472173
}
22482174

2175+
/**
2176+
* Converts a source object into {@link TypeInformation target}.
2177+
*
2178+
* @param source must not be {@literal null}.
2179+
* @param typeHint must not be {@literal null}.
2180+
* @param context must not be {@literal null}.
2181+
* @return the converted object.
2182+
*/
22492183
<S extends Object> S convert(Object source, TypeInformation<? extends S> typeHint, ConversionContext context);
22502184

2185+
/**
2186+
* Create a new {@link ConversionContext} with {@link ObjectPath currentPath} applied.
2187+
*
2188+
* @param currentPath must not be {@literal null}.
2189+
* @return a new {@link ConversionContext} with {@link ObjectPath currentPath} applied.
2190+
*/
22512191
ConversionContext withPath(ObjectPath currentPath);
22522192

2253-
ObjectPath getPath();
2254-
2193+
/**
2194+
* Obtain a {@link ConversionContext} for the given property {@code name}.
2195+
*
2196+
* @param name must not be {@literal null}.
2197+
* @return the {@link ConversionContext} to be used for conversion of the given property.
2198+
*/
22552199
default ConversionContext forProperty(String name) {
22562200
return this;
22572201
}
22582202

2259-
default ConversionContext forProperty(@Nullable PersistentProperty property) {
2203+
/**
2204+
* Obtain a {@link ConversionContext} for the given {@link MongoPersistentProperty}.
2205+
*
2206+
* @param property must not be {@literal null}.
2207+
* @return the {@link ConversionContext} to be used for conversion of the given property.
2208+
*/
2209+
default ConversionContext forProperty(MongoPersistentProperty property) {
22602210

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;
2211+
return property.isAssociation() ? new AssociationConversionContext(forProperty(property.getName()))
2212+
: forProperty(property.getName());
22682213
}
22692214

2270-
default boolean resolveIdsInContext() {
2271-
return false;
2215+
/**
2216+
* Lookup a potentially existing entity instance of the given {@link MongoPersistentEntity} and {@link Document}
2217+
*
2218+
* @param entity
2219+
* @param document
2220+
* @return
2221+
* @param <S>
2222+
*/
2223+
@Nullable
2224+
default <S> S findContextualEntity(MongoPersistentEntity<S> entity, Document document) {
2225+
return null;
22722226
}
22732227

2228+
ObjectPath getPath();
2229+
22742230
CustomConversions getCustomConversions();
22752231

22762232
MongoConverter getSourceConverter();
2233+
2234+
}
2235+
2236+
/**
2237+
* @since 3.4.3
2238+
*/
2239+
static class AssociationConversionContext implements ConversionContext {
2240+
2241+
private final ConversionContext delegate;
2242+
2243+
public AssociationConversionContext(ConversionContext delegate) {
2244+
this.delegate = delegate;
2245+
}
2246+
2247+
@Override
2248+
public <S> S convert(Object source, TypeInformation<? extends S> typeHint, ConversionContext context) {
2249+
return delegate.convert(source, typeHint, context);
2250+
}
2251+
2252+
@Override
2253+
public ConversionContext withPath(ObjectPath currentPath) {
2254+
return new AssociationConversionContext(delegate.withPath(currentPath));
2255+
}
2256+
2257+
@Override
2258+
public <S> S findContextualEntity(MongoPersistentEntity<S> entity, Document document) {
2259+
2260+
Object identifier = document.get(BasicMongoPersistentProperty.ID_FIELD_NAME);
2261+
2262+
return identifier != null ? getPath().getPathItem(identifier, entity.getCollection(), entity.getType()) : null;
2263+
}
2264+
2265+
@Override
2266+
public ObjectPath getPath() {
2267+
return delegate.getPath();
2268+
}
2269+
2270+
@Override
2271+
public CustomConversions getCustomConversions() {
2272+
return delegate.getCustomConversions();
2273+
}
2274+
2275+
@Override
2276+
public MongoConverter getSourceConverter() {
2277+
return delegate.getSourceConverter();
2278+
}
2279+
22772280
}
22782281

22792282
/**
@@ -2309,14 +2312,8 @@ protected static class DefaultConversionContext implements ConversionContext {
23092312
this.elementConverter = elementConverter;
23102313
}
23112314

2312-
/**
2313-
* Converts a source object into {@link TypeInformation target}.
2314-
*
2315-
* @param source must not be {@literal null}.
2316-
* @param typeHint must not be {@literal null}.
2317-
* @return the converted object.
2318-
*/
23192315
@SuppressWarnings("unchecked")
2316+
@Override
23202317
public <S extends Object> S convert(Object source, TypeInformation<? extends S> typeHint,
23212318
ConversionContext context) {
23222319

@@ -2382,28 +2379,20 @@ public MongoConverter getSourceConverter() {
23822379
return sourceConverter;
23832380
}
23842381

2385-
/**
2386-
* Create a new {@link DefaultConversionContext} with {@link ObjectPath currentPath} applied.
2387-
*
2388-
* @param currentPath must not be {@literal null}.
2389-
* @return a new {@link DefaultConversionContext} with {@link ObjectPath currentPath} applied.
2390-
*/
2391-
public DefaultConversionContext withPath(ObjectPath currentPath) {
2382+
@Override
2383+
public ConversionContext withPath(ObjectPath currentPath) {
23922384

23932385
Assert.notNull(currentPath, "ObjectPath must not be null");
23942386

23952387
return new DefaultConversionContext(sourceConverter, conversions, currentPath, documentConverter,
23962388
collectionConverter, mapConverter, dbRefConverter, elementConverter);
23972389
}
23982390

2391+
@Override
23992392
public ObjectPath getPath() {
24002393
return path;
24012394
}
24022395

2403-
public DefaultConversionContext forProperty(String name) {
2404-
return this;
2405-
}
2406-
24072396
/**
24082397
* Converts a simple {@code source} value into {@link TypeInformation the target type}.
24092398
*
@@ -2429,6 +2418,45 @@ interface ContainerValueConverter<T> {
24292418

24302419
}
24312420

2421+
/**
2422+
* @since 3.4.3
2423+
*/
2424+
class ProjectingConversionContext extends DefaultConversionContext {
2425+
2426+
private final EntityProjection<?, ?> returnedTypeDescriptor;
2427+
2428+
ProjectingConversionContext(MongoConverter sourceConverter, CustomConversions customConversions, ObjectPath path,
2429+
ContainerValueConverter<Collection<?>> collectionConverter, ContainerValueConverter<Bson> mapConverter,
2430+
ContainerValueConverter<DBRef> dbRefConverter, ValueConverter<Object> elementConverter,
2431+
EntityProjection<?, ?> projection) {
2432+
super(sourceConverter, customConversions, path,
2433+
(context, source, typeHint) -> doReadOrProject(context, source, typeHint, projection),
2434+
2435+
collectionConverter, mapConverter, dbRefConverter, elementConverter);
2436+
this.returnedTypeDescriptor = projection;
2437+
}
2438+
2439+
@Override
2440+
public ConversionContext forProperty(String name) {
2441+
2442+
EntityProjection<?, ?> property = returnedTypeDescriptor.findProperty(name);
2443+
if (property == null) {
2444+
return new DefaultConversionContext(sourceConverter, conversions, path,
2445+
MappingMongoConverter.this::readDocument, collectionConverter, mapConverter, dbRefConverter,
2446+
elementConverter);
2447+
}
2448+
2449+
return new ProjectingConversionContext(sourceConverter, conversions, path, collectionConverter, mapConverter,
2450+
dbRefConverter, elementConverter, property);
2451+
}
2452+
2453+
@Override
2454+
public ConversionContext withPath(ObjectPath currentPath) {
2455+
return new ProjectingConversionContext(sourceConverter, conversions, currentPath, collectionConverter,
2456+
mapConverter, dbRefConverter, elementConverter, returnedTypeDescriptor);
2457+
}
2458+
}
2459+
24322460
private static class PropertyTranslatingPropertyAccessor<T> implements PersistentPropertyPathAccessor<T> {
24332461

24342462
private final PersistentPropertyAccessor<T> delegate;

0 commit comments

Comments
 (0)