Browse Source

DATAMONGO-1118 - MappingMongoConverter now uses custom conversions for Map keys, too.

We now allow conversions of map keys using custom Converter implementations if the conversion target type is a String.

Original pull request: #260.
pull/263/head
Christoph Strobl 11 years ago committed by Oliver Gierke
parent
commit
c353e02b3e
  1. 19
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
  2. 112
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java

19
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java

@ -646,9 +646,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -646,9 +646,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
Object key = entry.getKey();
Object val = entry.getValue();
if (conversions.isSimpleType(key.getClass())) {
// Don't use conversion service here as removal of ObjectToString converter results in some primitive types not
// being convertable
String simpleKey = potentiallyEscapeMapKey(key.toString());
String simpleKey = potentiallyConvertMapKey(key);
if (val == null || conversions.isSimpleType(val.getClass())) {
writeSimpleInternal(val, dbo, simpleKey);
} else if (val instanceof Collection || val.getClass().isArray()) {
@ -669,6 +668,20 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App @@ -669,6 +668,20 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return dbo;
}
private String potentiallyConvertMapKey(Object key) {
String stringKey = null;
if (key instanceof String
|| !(conversions.hasCustomWriteTarget(key.getClass()) && conversions.getCustomWriteTarget(key.getClass())
.equals(String.class))) {
stringKey = key.toString();
} else {
stringKey = (String) getPotentiallyConvertedSimpleWrite(key);
}
return potentiallyEscapeMapKey(stringKey);
}
/**
* Potentially replaces dots in the given map key with the configured map key replacement if configured or aborts
* conversion if none is configured.

112
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java

@ -56,12 +56,15 @@ import org.mockito.Mock; @@ -56,12 +56,15 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.geo.Box;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
@ -1964,6 +1967,7 @@ public class MappingMongoConverterUnitTests { @@ -1964,6 +1967,7 @@ public class MappingMongoConverterUnitTests {
assertThat(converter.read(TypeWithLocalDateTime.class, result).date, is(reference));
}
/**
* @see DATAMONGO-1128
*/
@ -2001,6 +2005,68 @@ public class MappingMongoConverterUnitTests { @@ -2001,6 +2005,68 @@ public class MappingMongoConverterUnitTests {
assertThat(read.localDateTime, is(Optional.of(now)));
}
/**
* @see DATAMONGO-1118
*/
@Test
public void convertsMapKeyUsingCustomConverterForAndBackwards() {
MappingMongoConverter converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(new CustomConversions(Arrays.asList(new FooBarEnumToStringConverter(),
new StringToFooNumConverter())));
converter.afterPropertiesSet();
ClassWithMapUsingEnumAsKey source = new ClassWithMapUsingEnumAsKey();
source.map = new HashMap<MappingMongoConverterUnitTests.FooBarEnum, String>();
source.map.put(FooBarEnum.FOO, "wohoo");
DBObject target = new BasicDBObject();
converter.write(source, target);
assertThat(converter.read(ClassWithMapUsingEnumAsKey.class, target).map, equalTo(source.map));
}
/**
* @see DATAMONGO-1118
*/
@Test
public void writesMapKeyUsingCustomConverter() {
MappingMongoConverter converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(new CustomConversions(Arrays.asList(new FooBarEnumToStringConverter())));
converter.afterPropertiesSet();
ClassWithMapUsingEnumAsKey source = new ClassWithMapUsingEnumAsKey();
source.map = new HashMap<MappingMongoConverterUnitTests.FooBarEnum, String>();
source.map.put(FooBarEnum.FOO, "spring");
source.map.put(FooBarEnum.BAR, "data");
DBObject target = new BasicDBObject();
converter.write(source, target);
DBObject map = DBObjectTestUtils.getAsDBObject(target, "map");
assertThat(map.containsField("foo-enum-value"), is(true));
assertThat(map.containsField("bar-enum-value"), is(true));
}
/**
* @see DATAMONGO-1118
*/
@Test
public void readsMapKeyUsingCustomConverter() {
MappingMongoConverter converter = new MappingMongoConverter(resolver, mappingContext);
converter.setCustomConversions(new CustomConversions(Arrays.asList(new StringToFooNumConverter())));
converter.afterPropertiesSet();
DBObject source = new BasicDBObject("map", new BasicDBObject("foo-enum-value", "spring"));
ClassWithMapUsingEnumAsKey target = converter.read(ClassWithMapUsingEnumAsKey.class, source);
assertThat(target.map.get(FooBarEnum.FOO), is("spring"));
}
static class GenericType<T> {
T content;
}
@ -2303,4 +2369,50 @@ public class MappingMongoConverterUnitTests { @@ -2303,4 +2369,50 @@ public class MappingMongoConverterUnitTests {
Optional<String> string = Optional.empty();
Optional<LocalDateTime> localDateTime = Optional.empty();
}
static enum FooBarEnum {
FOO, BAR;
}
static class ClassWithMapUsingEnumAsKey {
Map<FooBarEnum, String> map;
}
@WritingConverter
static class FooBarEnumToStringConverter implements Converter<FooBarEnum, String> {
@Override
public String convert(FooBarEnum source) {
if (source == null) {
return null;
}
return FooBarEnum.FOO.equals(source) ? "foo-enum-value" : "bar-enum-value";
}
}
@ReadingConverter
static class StringToFooNumConverter implements Converter<String, FooBarEnum> {
@Override
public FooBarEnum convert(String source) {
if (source == null) {
return null;
}
if (source.equals("foo-enum-value")) {
return FooBarEnum.FOO;
}
if (source.equals("bar-enum-value")) {
return FooBarEnum.BAR;
}
throw new ConversionNotSupportedException(source, String.class, null);
}
}
}

Loading…
Cancel
Save