DATADOC-235 - Arbitrary Map values are now converted correctly.

Map values are now handled correctly regardless of the actual Map value type declaration (can be Object in the most open case). We now handle collections as Map value types correctly. BasicDBList instances are now hinted to become Lists by default (if not typed to another collection type by the property). 

Reduced visibility of MappingMongoConverter.addCustomTypeKeyIfNecessary(…) and made createCollectionDBObject(…) safe against null values for the TypeInformation.
This commit is contained in:
Oliver Gierke
2011-08-15 20:54:16 +02:00
parent 35f180f999
commit 2016aab969
2 changed files with 91 additions and 5 deletions

View File

@@ -149,7 +149,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
TypeInformation<? extends S> typeToUse = getMoreConcreteTargetType(dbo, type);
Class<? extends S> rawType = typeToUse.getType();
if (conversions.hasCustomReadTarget(DBObject.class, rawType)) {
if (conversions.hasCustomReadTarget(dbo.getClass(), rawType)) {
return conversionService.convert(dbo, rawType);
}
@@ -513,14 +513,14 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
/**
* Creates a new {@link BasicDBList} from the given {@link Collection}.
*
* @param type
* @param source
* @param type the {@link TypeInformation} to consider or {@literal null} if unknown.
* @param source the collection to create a {@link BasicDBList} for, must not be {@literal null}.
* @return
*/
private BasicDBList createCollectionDBObject(TypeInformation<?> type, Collection<?> source) {
BasicDBList dbList = new BasicDBList();
TypeInformation<?> componentType = type.getComponentType();
TypeInformation<?> componentType = type == null ? null : type.getComponentType();
for (Object element : source) {
@@ -556,6 +556,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
String simpleKey = key.toString();
if (val == null || conversions.isSimpleType(val.getClass())) {
writeSimpleInternal(simpleKey, val, dbo);
} else if (val instanceof Collection) {
dbo.put(simpleKey, createCollectionDBObject(propertyType.getMapValueType(), (Collection<?>) val));
} else {
DBObject newDbo = new BasicDBObject();
writeInternal(val, newDbo);
@@ -576,7 +578,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
* @param value
* @param dbObject
*/
public void addCustomTypeKeyIfNecessary(TypeInformation<?> type, Object value, DBObject dbObject) {
protected void addCustomTypeKeyIfNecessary(TypeInformation<?> type, Object value, DBObject dbObject) {
if (type == null) {
return;
@@ -801,6 +803,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
* found.
*/
protected Class<?> findTypeToBeUsed(DBObject dbObject) {
if (dbObject instanceof BasicDBList) {
return List.class;
}
Object classToBeUsed = dbObject.get(CUSTOM_TYPE_KEY);
if (classToBeUsed == null) {

View File

@@ -528,6 +528,83 @@ public class MappingMongoConverterUnitTests {
assertThat(converter.convertToMongoType(id), is((Object) id));
}
/**
* @see DATADOC-235
*/
@Test
public void writesMapOfListsCorrectly() {
ClassWithMapProperty input = new ClassWithMapProperty();
input.mapOfLists = Collections.singletonMap("Foo", Arrays.asList("Bar"));
BasicDBObject result = new BasicDBObject();
converter.write(input, result);
Object field = result.get("mapOfLists");
assertThat(field, is(instanceOf(DBObject.class)));
DBObject map = (DBObject) field;
Object foo = map.get("Foo");
assertThat(foo, is(instanceOf(BasicDBList.class)));
BasicDBList value = (BasicDBList) foo;
assertThat(value.size(), is(1));
assertThat((String) value.get(0), is("Bar"));
}
/**
* @see DATADOC-235
*/
@Test
public void readsMapListValuesCorrectly() {
BasicDBList list = new BasicDBList();
list.add("Bar");
DBObject source = new BasicDBObject("mapOfLists", new BasicDBObject("Foo", list));
ClassWithMapProperty result = converter.read(ClassWithMapProperty.class, source);
assertThat(result.mapOfLists, is(not(nullValue())));
}
/**
* @see DATADOC-235
*/
@Test
public void writesMapsOfObjectsCorrectly() {
ClassWithMapProperty input = new ClassWithMapProperty();
input.mapOfObjects = new HashMap<String, Object>();
input.mapOfObjects.put("Foo", Arrays.asList("Bar"));
BasicDBObject result = new BasicDBObject();
converter.write(input, result);
Object field = result.get("mapOfObjects");
assertThat(field, is(instanceOf(DBObject.class)));
DBObject map = (DBObject) field;
Object foo = map.get("Foo");
assertThat(foo, is(instanceOf(BasicDBList.class)));
BasicDBList value = (BasicDBList) foo;
assertThat(value.size(), is(1));
assertThat((String) value.get(0), is("Bar"));
}
/**
* @see DATADOC-235
*/
@Test
public void readsMapOfObjectsListValuesCorrectly() {
BasicDBList list = new BasicDBList();
list.add("Bar");
DBObject source = new BasicDBObject("mapOfObjects", new BasicDBObject("Foo", list));
ClassWithMapProperty result = converter.read(ClassWithMapProperty.class, source);
assertThat(result.mapOfObjects, is(not(nullValue())));
}
class GenericType<T> {
T content;
}
@@ -566,6 +643,8 @@ public class MappingMongoConverterUnitTests {
class ClassWithMapProperty {
Map<Locale, String> map;
Map<String, List<String>> mapOfLists;
Map<String, Object> mapOfObjects;
}
class ClassWithNestedMaps {