DATADOC-245 - MappingMongoConverter now reads nested, untyped Maps correctly.

Added some defaulting code in MappingMongoConverter that converts DBObject instances into Maps in case the raw property type is Object (see getMoreConcreteTargetType()).
This commit is contained in:
Oliver Gierke
2011-08-19 22:43:26 +02:00
parent dd02338b5e
commit b01e1a994b
2 changed files with 52 additions and 16 deletions

View File

@@ -79,6 +79,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
private static final List<Class<?>> VALID_ID_TYPES = Arrays.asList(new Class<?>[] { ObjectId.class, String.class,
BigInteger.class, byte[].class });
private static final TypeInformation<Map> MAP_TYPE_INFORMATION = ClassTypeInformation.from(Map.class);
protected static final Log log = LogFactory.getLog(MappingMongoConverter.class);
protected final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
@@ -174,6 +176,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
}
return conversionService.convert(l, rawType);
}
if (typeToUse.isMap()) {
return (S) readMap(typeToUse, dbo);
}
// Retrieve persistent entity info
MongoPersistentEntity<S> persistentEntity = (MongoPersistentEntity<S>) mappingContext
@@ -638,6 +644,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
@SuppressWarnings({ "rawtypes", "unchecked" })
private Object getPotentiallyConvertedSimpleRead(Object value, Class<?> target) {
Assert.notNull(target);
if (value == null) {
return null;
}
@@ -761,10 +769,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
@SuppressWarnings("unchecked")
protected Map<Object, Object> readMap(TypeInformation<?> type, DBObject dbObject) {
Assert.notNull(type);
Assert.isTrue(type.isMap());
Assert.notNull(dbObject);
type = type == null ? MAP_TYPE_INFORMATION : type;
Class<?> customMapType = findTypeToBeUsed(dbObject);
Class<?> mapType = customMapType == null ? type.getType() : customMapType;
@@ -776,19 +783,26 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
continue;
}
Class<?> keyType = type.getComponentType().getType();
Object key = conversionService.convert(entry.getKey(), keyType);
Object key = entry.getKey();
TypeInformation<?> keyTypeInformation = type.getComponentType();
if (keyTypeInformation != null) {
Class<?> keyType = keyTypeInformation.getType();
key = conversionService.convert(entry.getKey(), keyType);
}
Object value = entry.getValue();
TypeInformation<?> valueType = type.getMapValueType();
valueType = valueType == null ? MAP_TYPE_INFORMATION : valueType;
if (null != entry.getValue() && entry.getValue() instanceof DBObject) {
DBObject valueSource = (DBObject) entry.getValue();
TypeInformation<?> valueType = type.getMapValueType();
Object value = valueType.isMap() ? readMap(valueType, valueSource) : read(valueType, valueSource);
map.put(key, value);
if (value instanceof BasicDBList) {
BasicDBList list =(BasicDBList) value;
map.put(key, read(valueType, list));
} else if (value instanceof DBObject) {
DBObject valueSource = (DBObject) value;
map.put(key, valueType.isMap() ? readMap(valueType, valueSource) : read(valueType, valueSource));
} else {
map.put(key, getPotentiallyConvertedSimpleRead(entry.getValue(), type.getMapValueType().getType()));
map.put(key, getPotentiallyConvertedSimpleRead(value, valueType.getType()));
}
}
@@ -835,9 +849,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
private <S> TypeInformation<? extends S> getMoreConcreteTargetType(DBObject dbObject, TypeInformation<S> basicType) {
Class<?> documentsTargetType = findTypeToBeUsed(dbObject);
Class<S> rawType = basicType.getType();
if (documentsTargetType == null && Object.class.equals(rawType)) {
return (TypeInformation<? extends S>) MAP_TYPE_INFORMATION;
}
boolean isMoreConcreteCustomType = documentsTargetType != null && rawType.isAssignableFrom(documentsTargetType);
return isMoreConcreteCustomType ? (TypeInformation<? extends S>) ClassTypeInformation.from(documentsTargetType)
: basicType;
return isMoreConcreteCustomType ? (TypeInformation<? extends S>) ClassTypeInformation.from(documentsTargetType) : basicType;
}
protected <T> List<?> unwrapList(BasicDBList dbList, TypeInformation<T> targetType) {

View File

@@ -605,6 +605,24 @@ public class MappingMongoConverterUnitTests {
assertThat(result.mapOfObjects, is(not(nullValue())));
}
/**
* @see DATADOC-245
*/
@Test
public void readsMapListNestedValuesCorrectly() {
BasicDBList list = new BasicDBList();
BasicDBObject nested = new BasicDBObject();
nested.append("Hello", "World");
list.add(nested);
DBObject source = new BasicDBObject("mapOfObjects", new BasicDBObject("Foo", list));
ClassWithMapProperty result = converter.read(ClassWithMapProperty.class, source);
Object firstObjectInFoo = ((List<?>) result.mapOfObjects.get("Foo")).get(0);
assertThat(firstObjectInFoo, is(instanceOf(Map.class)));
assertThat((String)((Map<?,?>) firstObjectInFoo).get("Hello"), is(equalTo("World")));
}
class GenericType<T> {
T content;
}