Skip to content

Commit c353e02

Browse files
christophstroblodrotbohm
authored andcommitted
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.
1 parent 1c2964c commit c353e02

File tree

2 files changed

+128
-3
lines changed

2 files changed

+128
-3
lines changed

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

+16-3
Original file line numberDiff line numberDiff line change
@@ -646,9 +646,8 @@ protected DBObject writeMapInternal(Map<Object, Object> obj, DBObject dbo, TypeI
646646
Object key = entry.getKey();
647647
Object val = entry.getValue();
648648
if (conversions.isSimpleType(key.getClass())) {
649-
// Don't use conversion service here as removal of ObjectToString converter results in some primitive types not
650-
// being convertable
651-
String simpleKey = potentiallyEscapeMapKey(key.toString());
649+
650+
String simpleKey = potentiallyConvertMapKey(key);
652651
if (val == null || conversions.isSimpleType(val.getClass())) {
653652
writeSimpleInternal(val, dbo, simpleKey);
654653
} else if (val instanceof Collection || val.getClass().isArray()) {
@@ -669,6 +668,20 @@ protected DBObject writeMapInternal(Map<Object, Object> obj, DBObject dbo, TypeI
669668
return dbo;
670669
}
671670

671+
private String potentiallyConvertMapKey(Object key) {
672+
673+
String stringKey = null;
674+
if (key instanceof String
675+
|| !(conversions.hasCustomWriteTarget(key.getClass()) && conversions.getCustomWriteTarget(key.getClass())
676+
.equals(String.class))) {
677+
stringKey = key.toString();
678+
} else {
679+
stringKey = (String) getPotentiallyConvertedSimpleWrite(key);
680+
}
681+
682+
return potentiallyEscapeMapKey(stringKey);
683+
}
684+
672685
/**
673686
* Potentially replaces dots in the given map key with the configured map key replacement if configured or aborts
674687
* conversion if none is configured.

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

+112
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,15 @@
5656
import org.mockito.Mockito;
5757
import org.mockito.runners.MockitoJUnitRunner;
5858
import org.springframework.aop.framework.ProxyFactory;
59+
import org.springframework.beans.ConversionNotSupportedException;
5960
import org.springframework.beans.factory.annotation.Value;
6061
import org.springframework.context.ApplicationContext;
6162
import org.springframework.core.convert.converter.Converter;
6263
import org.springframework.data.annotation.Id;
6364
import org.springframework.data.annotation.PersistenceConstructor;
6465
import org.springframework.data.annotation.TypeAlias;
66+
import org.springframework.data.convert.ReadingConverter;
67+
import org.springframework.data.convert.WritingConverter;
6568
import org.springframework.data.geo.Box;
6669
import org.springframework.data.geo.Circle;
6770
import org.springframework.data.geo.Distance;
@@ -1964,6 +1967,7 @@ public void convertsJava8DateTimeTypesToDateAndBack() {
19641967
assertThat(converter.read(TypeWithLocalDateTime.class, result).date, is(reference));
19651968
}
19661969

1970+
19671971
/**
19681972
* @see DATAMONGO-1128
19691973
*/
@@ -2001,6 +2005,68 @@ public void readsOptionalsCorrectly() {
20012005
assertThat(read.localDateTime, is(Optional.of(now)));
20022006
}
20032007

2008+
/**
2009+
* @see DATAMONGO-1118
2010+
*/
2011+
@Test
2012+
public void convertsMapKeyUsingCustomConverterForAndBackwards() {
2013+
2014+
MappingMongoConverter converter = new MappingMongoConverter(resolver, mappingContext);
2015+
converter.setCustomConversions(new CustomConversions(Arrays.asList(new FooBarEnumToStringConverter(),
2016+
new StringToFooNumConverter())));
2017+
converter.afterPropertiesSet();
2018+
2019+
ClassWithMapUsingEnumAsKey source = new ClassWithMapUsingEnumAsKey();
2020+
source.map = new HashMap<MappingMongoConverterUnitTests.FooBarEnum, String>();
2021+
source.map.put(FooBarEnum.FOO, "wohoo");
2022+
2023+
DBObject target = new BasicDBObject();
2024+
converter.write(source, target);
2025+
2026+
assertThat(converter.read(ClassWithMapUsingEnumAsKey.class, target).map, equalTo(source.map));
2027+
}
2028+
2029+
/**
2030+
* @see DATAMONGO-1118
2031+
*/
2032+
@Test
2033+
public void writesMapKeyUsingCustomConverter() {
2034+
2035+
MappingMongoConverter converter = new MappingMongoConverter(resolver, mappingContext);
2036+
converter.setCustomConversions(new CustomConversions(Arrays.asList(new FooBarEnumToStringConverter())));
2037+
converter.afterPropertiesSet();
2038+
2039+
ClassWithMapUsingEnumAsKey source = new ClassWithMapUsingEnumAsKey();
2040+
source.map = new HashMap<MappingMongoConverterUnitTests.FooBarEnum, String>();
2041+
source.map.put(FooBarEnum.FOO, "spring");
2042+
source.map.put(FooBarEnum.BAR, "data");
2043+
2044+
DBObject target = new BasicDBObject();
2045+
converter.write(source, target);
2046+
2047+
DBObject map = DBObjectTestUtils.getAsDBObject(target, "map");
2048+
2049+
assertThat(map.containsField("foo-enum-value"), is(true));
2050+
assertThat(map.containsField("bar-enum-value"), is(true));
2051+
}
2052+
2053+
/**
2054+
* @see DATAMONGO-1118
2055+
*/
2056+
@Test
2057+
public void readsMapKeyUsingCustomConverter() {
2058+
2059+
MappingMongoConverter converter = new MappingMongoConverter(resolver, mappingContext);
2060+
converter.setCustomConversions(new CustomConversions(Arrays.asList(new StringToFooNumConverter())));
2061+
converter.afterPropertiesSet();
2062+
2063+
DBObject source = new BasicDBObject("map", new BasicDBObject("foo-enum-value", "spring"));
2064+
2065+
ClassWithMapUsingEnumAsKey target = converter.read(ClassWithMapUsingEnumAsKey.class, source);
2066+
2067+
assertThat(target.map.get(FooBarEnum.FOO), is("spring"));
2068+
}
2069+
20042070
static class GenericType<T> {
20052071
T content;
20062072
}
@@ -2303,4 +2369,50 @@ static class TypeWithOptional {
23032369
Optional<String> string = Optional.empty();
23042370
Optional<LocalDateTime> localDateTime = Optional.empty();
23052371
}
2372+
2373+
static enum FooBarEnum {
2374+
FOO, BAR;
2375+
}
2376+
2377+
static class ClassWithMapUsingEnumAsKey {
2378+
Map<FooBarEnum, String> map;
2379+
}
2380+
2381+
@WritingConverter
2382+
static class FooBarEnumToStringConverter implements Converter<FooBarEnum, String> {
2383+
2384+
@Override
2385+
public String convert(FooBarEnum source) {
2386+
if (source == null) {
2387+
return null;
2388+
}
2389+
2390+
return FooBarEnum.FOO.equals(source) ? "foo-enum-value" : "bar-enum-value";
2391+
}
2392+
2393+
}
2394+
2395+
@ReadingConverter
2396+
static class StringToFooNumConverter implements Converter<String, FooBarEnum> {
2397+
2398+
@Override
2399+
public FooBarEnum convert(String source) {
2400+
2401+
if (source == null) {
2402+
return null;
2403+
}
2404+
2405+
if (source.equals("foo-enum-value")) {
2406+
return FooBarEnum.FOO;
2407+
}
2408+
if (source.equals("bar-enum-value")) {
2409+
return FooBarEnum.BAR;
2410+
}
2411+
2412+
throw new ConversionNotSupportedException(source, String.class, null);
2413+
}
2414+
2415+
}
2416+
2417+
23062418
}

0 commit comments

Comments
 (0)