diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DBObjectAccessor.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DBObjectAccessor.java index 8e16a1554..a3d9cc9b1 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DBObjectAccessor.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/DBObjectAccessor.java @@ -75,9 +75,7 @@ class DBObjectAccessor { String part = parts.next(); if (parts.hasNext()) { - BasicDBObject nestedDbObject = new BasicDBObject(); - dbObject.put(part, nestedDbObject); - dbObject = nestedDbObject; + dbObject = getOrCreateNestedDbObject(part, dbObject); } else { dbObject.put(part, value); } @@ -116,8 +114,14 @@ class DBObjectAccessor { return result; } + /** + * Returns the given source object as map, i.e. {@link BasicDBObject}s and maps as is or {@literal null} otherwise. + * + * @param source can be {@literal null}. + * @return + */ @SuppressWarnings("unchecked") - private Map getAsMap(Object source) { + private static Map getAsMap(Object source) { if (source instanceof BasicDBObject) { return (BasicDBObject) source; @@ -129,4 +133,26 @@ class DBObjectAccessor { return null; } + + /** + * Returns the {@link DBObject} which either already exists in the given source under the given key, or creates a new + * nested one, registers it with the source and returns it. + * + * @param key must not be {@literal null} or empty. + * @param source must not be {@literal null}. + * @return + */ + private static DBObject getOrCreateNestedDbObject(String key, DBObject source) { + + Object existing = source.get(key); + + if (existing instanceof BasicDBObject) { + return (BasicDBObject) existing; + } + + DBObject nested = new BasicDBObject(); + source.put(key, nested); + + return nested; + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/DBObjectAccessorUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/DBObjectAccessorUnitTests.java index e476d7e1d..b4ad05236 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/DBObjectAccessorUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/DBObjectAccessorUnitTests.java @@ -79,6 +79,28 @@ public class DBObjectAccessorUnitTests { new DBObjectAccessor(null); } + /** + * @see DATAMONGO-1335 + */ + @Test + public void writesAllNestingsCorrectly() { + + MongoPersistentEntity entity = context.getPersistentEntity(TypeWithTwoNestings.class); + + BasicDBObject target = new BasicDBObject(); + + DBObjectAccessor accessor = new DBObjectAccessor(target); + accessor.put(entity.getPersistentProperty("id"), "id"); + accessor.put(entity.getPersistentProperty("b"), "b"); + accessor.put(entity.getPersistentProperty("c"), "c"); + + DBObject nestedA = DBObjectTestUtils.getAsDBObject(target, "a"); + + assertThat(nestedA, is(notNullValue())); + assertThat(nestedA.get("b"), is((Object) "b")); + assertThat(nestedA.get("c"), is((Object) "c")); + } + static class ProjectingType { String name; @@ -91,4 +113,10 @@ public class DBObjectAccessorUnitTests { String c; } + static class TypeWithTwoNestings { + + String id; + @Field("a.b") String b; + @Field("a.c") String c; + } }