diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java index 525146dd3..845546524 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java @@ -71,6 +71,7 @@ import com.mongodb.DBRef; * * @author Oliver Gierke * @author Jon Brisbin + * @author Patrik Wasik */ public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware { @@ -414,8 +415,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App } if (valueType.isMap()) { - BasicDBObject mapDbObj = new BasicDBObject(); - writeMapInternal((Map) obj, mapDbObj, type); + DBObject mapDbObj = createMap((Map) obj, prop); dbo.put(name, mapDbObj); return; } @@ -495,6 +495,42 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App return dbList; } + /** + * Writes the given {@link Map} using the given {@link MongoPersistentProperty} information. + * + * @param map must not {@literal null}. + * @param property must not be {@literal null}. + * @return + */ + protected DBObject createMap(Map map, MongoPersistentProperty property) { + + Assert.notNull(map, "Given map must not be null!"); + Assert.notNull(property, "PersistentProperty must not be null!"); + + if (!property.isDbReference()) { + return writeMapInternal(map, new BasicDBObject(), property.getTypeInformation()); + } + + BasicDBObject dbObject = new BasicDBObject(); + + for (Map.Entry entry : map.entrySet()) { + + Object key = entry.getKey(); + Object value = entry.getValue(); + + if (conversions.isSimpleType(key.getClass())) { + + String simpleKey = potentiallyEscapeMapKey(key.toString()); + dbObject.put(simpleKey, value != null ? createDBRef(value, property.getDBRef()) : null); + + } else { + throw new MappingException("Cannot use a complex object as a key value."); + } + } + + return dbObject; + } + /** * Populates the given {@link BasicDBList} with values from the given {@link Collection}. * diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java index 65be46cf9..2a12ccbaf 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java @@ -72,6 +72,7 @@ import com.mongodb.util.JSON; * Unit tests for {@link MappingMongoConverter}. * * @author Oliver Gierke + * @author Patrik Wasik */ @RunWith(MockitoJUnitRunner.class) public class MappingMongoConverterUnitTests { @@ -1321,6 +1322,53 @@ public class MappingMongoConverterUnitTests { converter.read(ObjectContainer.class, input); } + /** + * @see DATAMONGO-657 + */ + @Test + public void convertDocumentWithMapDBRef() { + + MapDBRef mapDBRef = new MapDBRef(); + + MapDBRefVal val = new MapDBRefVal(); + val.id = BigInteger.ONE; + + Map mapVal = new HashMap(); + mapVal.put("test", val); + + mapDBRef.map = mapVal; + + BasicDBObject dbObject = new BasicDBObject(); + converter.write(mapDBRef, dbObject); + + DBObject map = (DBObject) dbObject.get("map"); + + assertThat(map.get("test"), instanceOf(DBRef.class)); + + DBObject mapValDBObject = new BasicDBObject(); + mapValDBObject.put("_id", BigInteger.ONE); + + DBRef dbRef = mock(DBRef.class); + when(dbRef.fetch()).thenReturn(mapValDBObject); + + ((DBObject) dbObject.get("map")).put("test", dbRef); + + MapDBRef read = converter.read(MapDBRef.class, dbObject); + + assertThat(read.map.get("test").id, is(BigInteger.ONE)); + } + + @Document + class MapDBRef { + @org.springframework.data.mongodb.core.mapping.DBRef + Map map; + } + + @Document + class MapDBRefVal { + BigInteger id; + } + static class GenericType { T content; }