Skip to content

Commit 41aa498

Browse files
christophstroblodrotbohm
authored andcommitted
DATAMONGO-1236 - Update now include type hint correctly.
We now use property type information when mapping fields affected by an update in case we do not have proper entity information within the context. This allows more precise type resolution required for determining the need to write type hints for a given property. Original pull request: #301.
1 parent 74cead9 commit 41aa498

File tree

2 files changed

+119
-8
lines changed

2 files changed

+119
-8
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/UpdateMapper.java

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.springframework.core.convert.converter.Converter;
2323
import org.springframework.data.mapping.Association;
2424
import org.springframework.data.mapping.context.MappingContext;
25+
import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity;
2526
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
2627
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
2728
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty.PropertyToFieldNameConverter;
@@ -66,8 +67,8 @@ public UpdateMapper(MongoConverter converter) {
6667
*/
6768
@Override
6869
protected Object delegateConvertToMongoType(Object source, MongoPersistentEntity<?> entity) {
69-
return entity == null ? super.delegateConvertToMongoType(source, null)
70-
: converter.convertToMongoType(source, getTypeHintForEntity(entity));
70+
return entity == null ? super.delegateConvertToMongoType(source, null) : converter.convertToMongoType(source,
71+
getTypeHintForEntity(source, entity));
7172
}
7273

7374
/*
@@ -141,18 +142,21 @@ private DBObject getMappedValue(Field field, Modifier modifier) {
141142
return new BasicDBObject(modifier.getKey(), value);
142143
}
143144

144-
private TypeInformation<?> getTypeHintForEntity(MongoPersistentEntity<?> entity) {
145-
return processTypeHintForNestedDocuments(entity.getTypeInformation());
145+
private TypeInformation<?> getTypeHintForEntity(Object source, MongoPersistentEntity<?> entity) {
146+
return processTypeHintForNestedDocuments(source, entity.getTypeInformation());
146147
}
147148

148-
private TypeInformation<?> processTypeHintForNestedDocuments(TypeInformation<?> info) {
149+
private TypeInformation<?> processTypeHintForNestedDocuments(Object source, TypeInformation<?> info) {
149150

150151
Class<?> type = info.getActualType().getType();
151152
if (type.isInterface() || java.lang.reflect.Modifier.isAbstract(type.getModifiers())) {
152153
return info;
153154
}
154-
return NESTED_DOCUMENT;
155155

156+
if (!type.equals(source.getClass())) {
157+
return info;
158+
}
159+
return NESTED_DOCUMENT;
156160
}
157161

158162
/*
@@ -196,6 +200,18 @@ public MetadataBackedUpdateField(MongoPersistentEntity<?> entity, String key,
196200
this.key = key;
197201
}
198202

203+
@Override
204+
@SuppressWarnings({ "rawtypes", "unchecked" })
205+
public MongoPersistentEntity<?> getPropertyEntity() {
206+
207+
MongoPersistentEntity<?> entity = super.getPropertyEntity();
208+
if (entity != null || getProperty() == null) {
209+
return entity;
210+
}
211+
212+
return new BasicMongoPersistentEntity(getProperty().getTypeInformation());
213+
}
214+
199215
/*
200216
* (non-Javadoc)
201217
* @see org.springframework.data.mongodb.core.convert.QueryMapper.MetadataBackedField#getMappedKey()

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.Arrays;
2626
import java.util.Collections;
2727
import java.util.List;
28+
import java.util.Map;
2829

2930
import org.hamcrest.Matcher;
3031
import org.hamcrest.collection.IsIterableContainingInOrder;
@@ -610,8 +611,85 @@ public void mappingShouldRetainTypeInformationOfNestedListWhenUpdatingConcreteyP
610611
context.getPersistentEntity(DomainTypeWrappingConcreteyTypeHavingListOfInterfaceTypeAttributes.class));
611612

612613
assertThat(mappedUpdate, isBsonObject().notContaining("$set.concreteTypeWithListAttributeOfInterfaceType._class"));
613-
assertThat(mappedUpdate, isBsonObject()
614-
.containing("$set.concreteTypeWithListAttributeOfInterfaceType.models.[0]._class", ModelImpl.class.getName()));
614+
assertThat(
615+
mappedUpdate,
616+
isBsonObject().containing("$set.concreteTypeWithListAttributeOfInterfaceType.models.[0]._class",
617+
ModelImpl.class.getName()));
618+
}
619+
620+
/**
621+
* @see DATAMONGO-1236
622+
*/
623+
@Test
624+
public void mappingShouldRetainTypeInformationForObjectValues() {
625+
626+
Update update = new Update().set("value", new NestedDocument("kaladin"));
627+
DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
628+
context.getPersistentEntity(EntityWithObject.class));
629+
630+
assertThat(mappedUpdate, isBsonObject().containing("$set.value.name", "kaladin"));
631+
assertThat(mappedUpdate, isBsonObject().containing("$set.value._class", NestedDocument.class.getName()));
632+
}
633+
634+
/**
635+
* @see DATAMONGO-1236
636+
*/
637+
@Test
638+
public void mappingShouldNotRetainTypeInformationForConcreteValues() {
639+
640+
Update update = new Update().set("concreteValue", new NestedDocument("shallan"));
641+
DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
642+
context.getPersistentEntity(EntityWithObject.class));
643+
644+
assertThat(mappedUpdate, isBsonObject().containing("$set.concreteValue.name", "shallan"));
645+
assertThat(mappedUpdate, isBsonObject().notContaining("$set.concreteValue._class"));
646+
}
647+
648+
/**
649+
* @see DATAMONGO-1236
650+
*/
651+
@Test
652+
public void mappingShouldRetainTypeInformationForObjectValuesWithAlias() {
653+
654+
Update update = new Update().set("value", new NestedDocument("adolin"));
655+
DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
656+
context.getPersistentEntity(EntityWithAliasedObject.class));
657+
658+
assertThat(mappedUpdate, isBsonObject().containing("$set.renamed-value.name", "adolin"));
659+
assertThat(mappedUpdate, isBsonObject().containing("$set.renamed-value._class", NestedDocument.class.getName()));
660+
}
661+
662+
/**
663+
* @see DATAMONGO-1236
664+
*/
665+
@Test
666+
public void mappingShouldRetrainTypeInformationWhenValueTypeOfMapDoesNotMatchItsDeclaration() {
667+
668+
Map<Object, Object> map = Collections.<Object, Object> singletonMap("szeth", new NestedDocument("son-son-vallano"));
669+
670+
Update update = new Update().set("map", map);
671+
DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
672+
context.getPersistentEntity(EntityWithObjectMap.class));
673+
674+
assertThat(mappedUpdate, isBsonObject().containing("$set.map.szeth.name", "son-son-vallano"));
675+
assertThat(mappedUpdate, isBsonObject().containing("$set.map.szeth._class", NestedDocument.class.getName()));
676+
}
677+
678+
/**
679+
* @see DATAMONGO-1236
680+
*/
681+
@Test
682+
public void mappingShouldNotContainTypeInformationWhenValueTypeOfMapMatchesDeclaration() {
683+
684+
Map<Object, NestedDocument> map = Collections.<Object, NestedDocument> singletonMap("jasnah", new NestedDocument(
685+
"kholin"));
686+
687+
Update update = new Update().set("concreteMap", map);
688+
DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(),
689+
context.getPersistentEntity(EntityWithObjectMap.class));
690+
691+
assertThat(mappedUpdate, isBsonObject().containing("$set.concreteMap.jasnah.name", "kholin"));
692+
assertThat(mappedUpdate, isBsonObject().notContaining("$set.concreteMap.jasnah._class"));
615693
}
616694

617695
static class DomainTypeWrappingConcreteyTypeHavingListOfInterfaceTypeAttributes {
@@ -819,4 +897,21 @@ public NestedDocument(String name) {
819897
this.name = name;
820898
}
821899
}
900+
901+
static class EntityWithObject {
902+
903+
Object value;
904+
NestedDocument concreteValue;
905+
}
906+
907+
static class EntityWithAliasedObject {
908+
909+
@Field("renamed-value") Object value;
910+
}
911+
912+
static class EntityWithObjectMap {
913+
914+
Map<Object, Object> map;
915+
Map<Object, NestedDocument> concreteMap;
916+
}
822917
}

0 commit comments

Comments
 (0)