From 621b299f6f752c1c2741a066e9350db370d00ad1 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 26 Feb 2014 05:35:55 +0100 Subject: [PATCH] DATAMONGO-833 - Add support for reading EnumSets and EnumMaps. Switched to use Spring Data Commons' CollectionFactory that is capable of creating EnumSets and EnumMaps. Added unit test inspired by pull request #113 for EnumSets and an additional one for EnumMaps. Slightly refactored the algorithm for reading maps to prevent repeated type lookups. Related pull request: #113. --- .../core/convert/MappingMongoConverter.java | 28 ++++++------- .../MappingMongoConverterUnitTests.java | 39 +++++++++++++++++-- 2 files changed, 51 insertions(+), 16 deletions(-) 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 9da46304c..9bb8877f1 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 @@ -29,10 +29,10 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; -import org.springframework.core.CollectionFactory; import org.springframework.core.convert.ConversionException; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.ConversionServiceFactory; +import org.springframework.data.convert.CollectionFactory; import org.springframework.data.convert.EntityInstantiator; import org.springframework.data.convert.TypeMapper; import org.springframework.data.mapping.Association; @@ -794,7 +794,6 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App * @param sourceValue must not be {@literal null}. * @return the converted {@link Collection} or array, will never be {@literal null}. */ - @SuppressWarnings("unchecked") private Object readCollectionOrArray(TypeInformation targetType, BasicDBList sourceValue, Object parent) { Assert.notNull(targetType); @@ -805,13 +804,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App return getPotentiallyConvertedSimpleRead(new HashSet(), collectionType); } - collectionType = Collection.class.isAssignableFrom(collectionType) ? collectionType : List.class; - - Collection items = targetType.getType().isArray() ? new ArrayList() : CollectionFactory - .createCollection(collectionType, sourceValue.size()); TypeInformation componentType = targetType.getComponentType(); Class rawComponentType = componentType == null ? null : componentType.getType(); + collectionType = Collection.class.isAssignableFrom(collectionType) ? collectionType : List.class; + Collection items = targetType.getType().isArray() ? new ArrayList() : CollectionFactory + .createCollection(collectionType, rawComponentType, sourceValue.size()); + for (int i = 0; i < sourceValue.size(); i++) { Object dbObjItem = sourceValue.get(i); @@ -842,7 +841,14 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App Assert.notNull(dbObject); Class mapType = typeMapper.readType(dbObject, type).getType(); - Map map = CollectionFactory.createMap(mapType, dbObject.keySet().size()); + + TypeInformation keyType = type.getComponentType(); + Class rawKeyType = keyType == null ? null : keyType.getType(); + + TypeInformation valueType = type.getMapValueType(); + Class rawValueType = valueType == null ? null : valueType.getType(); + + Map map = CollectionFactory.createMap(mapType, rawKeyType, dbObject.keySet().size()); Map sourceMap = dbObject.toMap(); for (Entry entry : sourceMap.entrySet()) { @@ -852,15 +858,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App Object key = potentiallyUnescapeMapKey(entry.getKey()); - TypeInformation keyTypeInformation = type.getComponentType(); - if (keyTypeInformation != null) { - Class keyType = keyTypeInformation.getType(); - key = conversionService.convert(key, keyType); + if (rawKeyType != null) { + key = conversionService.convert(key, rawKeyType); } Object value = entry.getValue(); - TypeInformation valueType = type.getMapValueType(); - Class rawValueType = valueType == null ? null : valueType.getType(); if (value instanceof DBObject) { map.put(key, read(valueType, (DBObject) value, parent)); 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 0c2bb85ab..cb1cf72ca 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 @@ -28,6 +28,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; +import java.util.EnumMap; +import java.util.EnumSet; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; @@ -648,9 +650,7 @@ public class MappingMongoConverterUnitTests { public void readsMapListNestedValuesCorrectly() { BasicDBList list = new BasicDBList(); - BasicDBObject nested = new BasicDBObject(); - nested.append("Hello", "World"); - list.add(nested); + list.add(new BasicDBObject("Hello", "World")); DBObject source = new BasicDBObject("mapOfObjects", new BasicDBObject("Foo", list)); ClassWithMapProperty result = converter.read(ClassWithMapProperty.class, source); @@ -1454,6 +1454,37 @@ public class MappingMongoConverterUnitTests { assertThat(dbList.get(0), instanceOf(String.class)); } + /** + * @see DATAMONGO-833 + */ + @Test + public void readsEnumSetCorrectly() { + + BasicDBList enumSet = new BasicDBList(); + enumSet.add("SECOND"); + DBObject dbObject = new BasicDBObject("enumSet", enumSet); + + ClassWithEnumProperty result = converter.read(ClassWithEnumProperty.class, dbObject); + + assertThat(result.enumSet, is(instanceOf(EnumSet.class))); + assertThat(result.enumSet.size(), is(1)); + assertThat(result.enumSet, hasItem(SampleEnum.SECOND)); + } + + /** + * @see DATAMONGO-833 + */ + @Test + public void readsEnumMapCorrectly() { + + BasicDBObject enumMap = new BasicDBObject("FIRST", "Dave"); + ClassWithEnumProperty result = converter.read(ClassWithEnumProperty.class, new BasicDBObject("enumMap", enumMap)); + + assertThat(result.enumMap, is(instanceOf(EnumMap.class))); + assertThat(result.enumMap.size(), is(1)); + assertThat(result.enumMap.get(SampleEnum.FIRST), is("Dave")); + } + static class GenericType { T content; } @@ -1462,6 +1493,8 @@ public class MappingMongoConverterUnitTests { SampleEnum sampleEnum; List enums; + EnumSet enumSet; + EnumMap enumMap; } static enum SampleEnum {