Skip to content

Commit f301837

Browse files
christophstroblodrotbohm
authored andcommitted
DATAMONGO-807 - findAndModify(…) now retains type information.
Using findAndUpdate(…) did not retain type information when used to update a whole nested type instead of single fields within the type. We now use the UpdateMapper instead of QueryMapper in doFindAndModify(…). Original pull request: spring-projects#110.
1 parent 4d29d93 commit f301837

File tree

3 files changed

+94
-11
lines changed

3 files changed

+94
-11
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1565,8 +1565,8 @@ protected <T> T doFindAndModify(String collectionName, DBObject query, DBObject
15651565

15661566
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(entityClass);
15671567

1568-
DBObject mappedUpdate = queryMapper.getMappedObject(update.getUpdateObject(), entity);
15691568
DBObject mappedQuery = queryMapper.getMappedObject(query, entity);
1569+
DBObject mappedUpdate = updateMapper.getMappedObject(update.getUpdateObject(), entity);
15701570

15711571
if (LOGGER.isDebugEnabled()) {
15721572
LOGGER.debug("findAndModify using query: " + mappedQuery + " fields: " + fields + " sort: " + sort

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

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1803,12 +1803,12 @@ public void updatesShouldRetainTypeInformation() {
18031803

18041804
Document doc = new Document();
18051805
doc.id = "4711";
1806-
doc.model = new ModelA().withValue("foo");
1806+
doc.model = new ModelA("foo");
18071807
template.insert(doc);
18081808

18091809
Query query = new Query(Criteria.where("id").is(doc.id));
18101810
String newModelValue = "bar";
1811-
Update update = Update.update("model", new ModelA().withValue(newModelValue));
1811+
Update update = Update.update("model", new ModelA(newModelValue));
18121812
template.updateFirst(query, update, Document.class);
18131813

18141814
Document result = template.findOne(query, Document.class);
@@ -2185,26 +2185,43 @@ public void itShouldBePossibleToReuseAnExistingQuery() {
21852185
assertThat(template.find(query, Sample.class), is(not(empty())));
21862186
}
21872187

2188+
/**
2189+
* @see DATAMONGO-807
2190+
*/
2191+
@Test
2192+
public void findAndModifyShouldRetrainTypeInformationWithinUpdatedType() {
2193+
2194+
Document document = new Document();
2195+
document.model = new ModelA("value1");
2196+
2197+
template.save(document);
2198+
2199+
Query query = query(where("id").is(document.id));
2200+
Update update = Update.update("model", new ModelA("value2"));
2201+
template.findAndModify(query, update, Document.class);
2202+
2203+
Document retrieved = template.findOne(query, Document.class);
2204+
Assert.assertThat(retrieved.model, instanceOf(ModelA.class));
2205+
Assert.assertThat(retrieved.model.value(), equalTo("value2"));
2206+
}
2207+
21882208
static interface Model {
21892209
String value();
2190-
2191-
Model withValue(String value);
21922210
}
21932211

21942212
static class ModelA implements Model {
21952213

21962214
private String value;
21972215

2216+
ModelA(String value) {
2217+
this.value = value;
2218+
}
2219+
21982220
@Override
21992221
public String value() {
22002222
return this.value;
22012223
}
22022224

2203-
@Override
2204-
public Model withValue(String value) {
2205-
this.value = value;
2206-
return this;
2207-
}
22082225
}
22092226

22102227
static class Document {

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

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013 the original author or authors.
2+
* Copyright 2013-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -36,6 +36,7 @@
3636
* Unit tests for {@link UpdateMapper}.
3737
*
3838
* @author Oliver Gierke
39+
* @author Christoph Strobl
3940
*/
4041
@RunWith(MockitoJUnitRunner.class)
4142
public class UpdateMapperUnitTests {
@@ -69,6 +70,71 @@ public void updateMapperRetainsTypeInformationForCollectionField() {
6970
assertThat(list.get("_class"), is((Object) ConcreteChildClass.class.getName()));
7071
}
7172

73+
/**
74+
* @see DATAMONGO-807
75+
*/
76+
@Test
77+
public void updateMapperShouldRetainTypeInformationForNestedEntities() {
78+
79+
Update update = Update.update("model", new ModelImpl(1));
80+
UpdateMapper mapper = new UpdateMapper(converter);
81+
82+
DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
83+
context.getPersistentEntity(ModelWrapper.class));
84+
85+
DBObject set = DBObjectTestUtils.getAsDBObject(mappedObject, "$set");
86+
DBObject modelDbObject = (DBObject) set.get("model");
87+
assertThat(modelDbObject.get("_class"), not(nullValue()));
88+
}
89+
90+
/**
91+
* @see DATAMONGO-807
92+
*/
93+
@Test
94+
public void updateMapperShouldNotPersistTypeInformationForKnownSimpleTypes() {
95+
96+
Update update = Update.update("model.value", 1);
97+
UpdateMapper mapper = new UpdateMapper(converter);
98+
99+
DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
100+
context.getPersistentEntity(ModelWrapper.class));
101+
102+
DBObject set = DBObjectTestUtils.getAsDBObject(mappedObject, "$set");
103+
assertThat(set.get("_class"), nullValue());
104+
}
105+
106+
/**
107+
* @see DATAMONGO-807
108+
*/
109+
@Test
110+
public void updateMapperShouldNotPersistTypeInformationForNullValues() {
111+
112+
Update update = Update.update("model", null);
113+
UpdateMapper mapper = new UpdateMapper(converter);
114+
115+
DBObject mappedObject = mapper.getMappedObject(update.getUpdateObject(),
116+
context.getPersistentEntity(ModelWrapper.class));
117+
118+
DBObject set = DBObjectTestUtils.getAsDBObject(mappedObject, "$set");
119+
assertThat(set.get("_class"), nullValue());
120+
}
121+
122+
static interface Model {
123+
124+
}
125+
126+
static class ModelImpl implements Model {
127+
public int value;
128+
129+
public ModelImpl(int value) {
130+
this.value = value;
131+
}
132+
}
133+
134+
public class ModelWrapper {
135+
Model model;
136+
}
137+
72138
static class ParentClass {
73139

74140
String id;

0 commit comments

Comments
 (0)