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:
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user