Skip to content

Commit a3e4f44

Browse files
committed
DATAMONGO-1118 - Polishing.
Created dedicated prepareMapKey(…) method to chain calls to potentiallyConvertMapKey(…) and potentiallyEscapeMapKey(…) and make sure they always get applied in combination. Fixed initial map creation for DBRefs to apply the fixed behavior, too. Original pull request: spring-projects#260.
1 parent 4a7a485 commit a3e4f44

File tree

2 files changed

+42
-23
lines changed

2 files changed

+42
-23
lines changed

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

+31-11
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ protected DBObject createMap(Map<Object, Object> map, MongoPersistentProperty pr
591591

592592
if (conversions.isSimpleType(key.getClass())) {
593593

594-
String simpleKey = potentiallyEscapeMapKey(key.toString());
594+
String simpleKey = prepareMapKey(key.toString());
595595
dbObject.put(simpleKey, value != null ? createDBRef(value, property) : null);
596596

597597
} else {
@@ -643,11 +643,13 @@ private BasicDBList writeCollectionInternal(Collection<?> source, TypeInformatio
643643
protected DBObject writeMapInternal(Map<Object, Object> obj, DBObject dbo, TypeInformation<?> propertyType) {
644644

645645
for (Map.Entry<Object, Object> entry : obj.entrySet()) {
646+
646647
Object key = entry.getKey();
647648
Object val = entry.getValue();
649+
648650
if (conversions.isSimpleType(key.getClass())) {
649651

650-
String simpleKey = potentiallyEscapeMapKey(potentiallyConvertMapKey(key));
652+
String simpleKey = prepareMapKey(key);
651653
if (val == null || conversions.isSimpleType(val.getClass())) {
652654
writeSimpleInternal(val, dbo, simpleKey);
653655
} else if (val instanceof Collection || val.getClass().isArray()) {
@@ -668,17 +670,19 @@ protected DBObject writeMapInternal(Map<Object, Object> obj, DBObject dbo, TypeI
668670
return dbo;
669671
}
670672

671-
private String potentiallyConvertMapKey(Object key) {
672-
673-
if (key instanceof String) {
674-
return (String) key;
675-
}
673+
/**
674+
* Prepares the given {@link Map} key to be converted into a {@link String}. Will invoke potentially registered custom
675+
* conversions and escape dots from the result as they're not supported as {@link Map} key in MongoDB.
676+
*
677+
* @param key must not be {@literal null}.
678+
* @return
679+
*/
680+
private String prepareMapKey(Object key) {
676681

677-
if (conversions.hasCustomWriteTarget(key.getClass(), String.class)) {
678-
return (String) getPotentiallyConvertedSimpleWrite(key);
679-
}
682+
Assert.notNull(key, "Map key must not be null!");
680683

681-
return key.toString();
684+
String convertedKey = potentiallyConvertMapKey(key);
685+
return potentiallyEscapeMapKey(convertedKey);
682686
}
683687

684688
/**
@@ -703,6 +707,22 @@ protected String potentiallyEscapeMapKey(String source) {
703707
return source.replaceAll("\\.", mapKeyDotReplacement);
704708
}
705709

710+
/**
711+
* Returns a {@link String} representation of the given {@link Map} key
712+
*
713+
* @param key
714+
* @return
715+
*/
716+
private String potentiallyConvertMapKey(Object key) {
717+
718+
if (key instanceof String) {
719+
return (String) key;
720+
}
721+
722+
return conversions.hasCustomWriteTarget(key.getClass(), String.class) ? (String) getPotentiallyConvertedSimpleWrite(key)
723+
: key.toString();
724+
}
725+
706726
/**
707727
* Translates the map key replacements in the given key just read with a dot in case a map key replacement has been
708728
* configured.

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

+11-12
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
import org.springframework.data.mongodb.core.DBObjectTestUtils;
7878
import org.springframework.data.mongodb.core.convert.DBObjectAccessorUnitTests.NestedType;
7979
import org.springframework.data.mongodb.core.convert.DBObjectAccessorUnitTests.ProjectingType;
80+
import org.springframework.data.mongodb.core.convert.MappingMongoConverterUnitTests.ClassWithMapUsingEnumAsKey.FooBarEnum;
8081
import org.springframework.data.mongodb.core.geo.Sphere;
8182
import org.springframework.data.mongodb.core.mapping.Document;
8283
import org.springframework.data.mongodb.core.mapping.Field;
@@ -1967,7 +1968,6 @@ public void convertsJava8DateTimeTypesToDateAndBack() {
19671968
assertThat(converter.read(TypeWithLocalDateTime.class, result).date, is(reference));
19681969
}
19691970

1970-
19711971
/**
19721972
* @see DATAMONGO-1128
19731973
*/
@@ -2009,6 +2009,7 @@ public void readsOptionalsCorrectly() {
20092009
* @see DATAMONGO-1118
20102010
*/
20112011
@Test
2012+
@SuppressWarnings("unchecked")
20122013
public void convertsMapKeyUsingCustomConverterForAndBackwards() {
20132014

20142015
MappingMongoConverter converter = new MappingMongoConverter(resolver, mappingContext);
@@ -2017,13 +2018,13 @@ public void convertsMapKeyUsingCustomConverterForAndBackwards() {
20172018
converter.afterPropertiesSet();
20182019

20192020
ClassWithMapUsingEnumAsKey source = new ClassWithMapUsingEnumAsKey();
2020-
source.map = new HashMap<MappingMongoConverterUnitTests.FooBarEnum, String>();
2021+
source.map = new HashMap<FooBarEnum, String>();
20212022
source.map.put(FooBarEnum.FOO, "wohoo");
20222023

20232024
DBObject target = new BasicDBObject();
20242025
converter.write(source, target);
20252026

2026-
assertThat(converter.read(ClassWithMapUsingEnumAsKey.class, target).map, equalTo(source.map));
2027+
assertThat(converter.read(ClassWithMapUsingEnumAsKey.class, target).map, is(source.map));
20272028
}
20282029

20292030
/**
@@ -2037,7 +2038,7 @@ public void writesMapKeyUsingCustomConverter() {
20372038
converter.afterPropertiesSet();
20382039

20392040
ClassWithMapUsingEnumAsKey source = new ClassWithMapUsingEnumAsKey();
2040-
source.map = new HashMap<MappingMongoConverterUnitTests.FooBarEnum, String>();
2041+
source.map = new HashMap<FooBarEnum, String>();
20412042
source.map.put(FooBarEnum.FOO, "spring");
20422043
source.map.put(FooBarEnum.BAR, "data");
20432044

@@ -2370,11 +2371,12 @@ static class TypeWithOptional {
23702371
Optional<LocalDateTime> localDateTime = Optional.empty();
23712372
}
23722373

2373-
static enum FooBarEnum {
2374-
FOO, BAR;
2375-
}
2376-
23772374
static class ClassWithMapUsingEnumAsKey {
2375+
2376+
static enum FooBarEnum {
2377+
FOO, BAR;
2378+
}
2379+
23782380
Map<FooBarEnum, String> map;
23792381
}
23802382

@@ -2383,13 +2385,13 @@ static class FooBarEnumToStringConverter implements Converter<FooBarEnum, String
23832385

23842386
@Override
23852387
public String convert(FooBarEnum source) {
2388+
23862389
if (source == null) {
23872390
return null;
23882391
}
23892392

23902393
return FooBarEnum.FOO.equals(source) ? "foo-enum-value" : "bar-enum-value";
23912394
}
2392-
23932395
}
23942396

23952397
@ReadingConverter
@@ -2411,8 +2413,5 @@ public FooBarEnum convert(String source) {
24112413

24122414
throw new ConversionNotSupportedException(source, String.class, null);
24132415
}
2414-
24152416
}
2416-
2417-
24182417
}

0 commit comments

Comments
 (0)