Skip to content

Commit 18bf0da

Browse files
committed
DATAMONGO-1335 - DBObjectAccessor now writes all nested fields correctly.
Previously, DBObjectAccessor has always reset the in-between values when traversing nested properties. This caused previously written values to be erased if subsequent values are written. We now reuse an already existing BasicDBObject if present.
1 parent 1e9189a commit 18bf0da

File tree

2 files changed

+58
-4
lines changed

2 files changed

+58
-4
lines changed

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

+30-4
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,7 @@ public void put(MongoPersistentProperty prop, Object value) {
7575
String part = parts.next();
7676

7777
if (parts.hasNext()) {
78-
BasicDBObject nestedDbObject = new BasicDBObject();
79-
dbObject.put(part, nestedDbObject);
80-
dbObject = nestedDbObject;
78+
dbObject = getOrCreateNestedDbObject(part, dbObject);
8179
} else {
8280
dbObject.put(part, value);
8381
}
@@ -116,8 +114,14 @@ public Object get(MongoPersistentProperty property) {
116114
return result;
117115
}
118116

117+
/**
118+
* Returns the given source object as map, i.e. {@link BasicDBObject}s and maps as is or {@literal null} otherwise.
119+
*
120+
* @param source can be {@literal null}.
121+
* @return
122+
*/
119123
@SuppressWarnings("unchecked")
120-
private Map<String, Object> getAsMap(Object source) {
124+
private static Map<String, Object> getAsMap(Object source) {
121125

122126
if (source instanceof BasicDBObject) {
123127
return (BasicDBObject) source;
@@ -129,4 +133,26 @@ private Map<String, Object> getAsMap(Object source) {
129133

130134
return null;
131135
}
136+
137+
/**
138+
* Returns the {@link DBObject} which either already exists in the given source under the given key, or creates a new
139+
* nested one, registers it with the source and returns it.
140+
*
141+
* @param key must not be {@literal null} or empty.
142+
* @param source must not be {@literal null}.
143+
* @return
144+
*/
145+
private static DBObject getOrCreateNestedDbObject(String key, DBObject source) {
146+
147+
Object existing = source.get(key);
148+
149+
if (existing instanceof BasicDBObject) {
150+
return (BasicDBObject) existing;
151+
}
152+
153+
DBObject nested = new BasicDBObject();
154+
source.put(key, nested);
155+
156+
return nested;
157+
}
132158
}

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

+28
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,28 @@ public void rejectsNullDBObject() {
7979
new DBObjectAccessor(null);
8080
}
8181

82+
/**
83+
* @see DATAMONGO-1335
84+
*/
85+
@Test
86+
public void writesAllNestingsCorrectly() {
87+
88+
MongoPersistentEntity<?> entity = context.getPersistentEntity(TypeWithTwoNestings.class);
89+
90+
BasicDBObject target = new BasicDBObject();
91+
92+
DBObjectAccessor accessor = new DBObjectAccessor(target);
93+
accessor.put(entity.getPersistentProperty("id"), "id");
94+
accessor.put(entity.getPersistentProperty("b"), "b");
95+
accessor.put(entity.getPersistentProperty("c"), "c");
96+
97+
DBObject nestedA = DBObjectTestUtils.getAsDBObject(target, "a");
98+
99+
assertThat(nestedA, is(notNullValue()));
100+
assertThat(nestedA.get("b"), is((Object) "b"));
101+
assertThat(nestedA.get("c"), is((Object) "c"));
102+
}
103+
82104
static class ProjectingType {
83105

84106
String name;
@@ -91,4 +113,10 @@ static class NestedType {
91113
String c;
92114
}
93115

116+
static class TypeWithTwoNestings {
117+
118+
String id;
119+
@Field("a.b") String b;
120+
@Field("a.c") String c;
121+
}
94122
}

0 commit comments

Comments
 (0)