From f70aa9e2d8ec4dcd549c2e12c7f120e106db892b Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Fri, 24 Nov 2023 14:21:21 +0100 Subject: [PATCH 1/3] Prepare issue branch. --- pom.xml | 2 +- spring-data-mongodb-benchmarks/pom.xml | 2 +- spring-data-mongodb-distribution/pom.xml | 2 +- spring-data-mongodb/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index aff1afc489..393f2f3b00 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 4.3.0-SNAPSHOT + 4.3.x-4567-SNAPSHOT pom Spring Data MongoDB diff --git a/spring-data-mongodb-benchmarks/pom.xml b/spring-data-mongodb-benchmarks/pom.xml index 34d95eb205..8a3df0ad44 100644 --- a/spring-data-mongodb-benchmarks/pom.xml +++ b/spring-data-mongodb-benchmarks/pom.xml @@ -7,7 +7,7 @@ org.springframework.data spring-data-mongodb-parent - 4.3.0-SNAPSHOT + 4.3.x-4567-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml index 124a6bf5ad..47738c09a4 100644 --- a/spring-data-mongodb-distribution/pom.xml +++ b/spring-data-mongodb-distribution/pom.xml @@ -15,7 +15,7 @@ org.springframework.data spring-data-mongodb-parent - 4.3.0-SNAPSHOT + 4.3.x-4567-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 39fc1a1de9..c0ac69f6ec 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -13,7 +13,7 @@ org.springframework.data spring-data-mongodb-parent - 4.3.0-SNAPSHOT + 4.3.x-4567-SNAPSHOT ../pom.xml From 1c89fe1053464adedf1d6b35745b9375d5b15599 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Fri, 24 Nov 2023 14:48:39 +0100 Subject: [PATCH 2/3] Fix NPE when traversing map. --- .../mongodb/core/convert/QueryMapper.java | 23 +++++++++++-------- .../core/convert/UpdateMapperUnitTests.java | 12 ++++++++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java index 30f8e47a09..5c1d137ccd 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/QueryMapper.java @@ -617,15 +617,20 @@ protected Object convertSimpleOrDocument(Object source, @Nullable MongoPersisten if (source instanceof Map sourceMap) { - return sourceMap.entrySet().stream().collect(Collectors.toMap( - entry -> ObjectUtils.nullSafeToString(converter.convertToMongoType(entry.getKey())), - entry -> { - if (entry.getValue() instanceof Document document) { - return getMappedObject(document, entity); - } - return delegateConvertToMongoType(entry.getValue(), entity); - } - )); + Map map = new LinkedHashMap<>(sourceMap.size(), 1F); + + sourceMap.entrySet().forEach(it -> { + + String key = ObjectUtils.nullSafeToString(converter.convertToMongoType(it.getKey())); + + if (it.getValue() instanceof Document document) { + map.put(key, getMappedObject(document, entity)); + } else { + map.put(key, delegateConvertToMongoType(it.getValue(), entity)); + } + }); + + return map; } return delegateConvertToMongoType(source, entity); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java index df1e13aeae..d9c7496138 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java @@ -762,6 +762,18 @@ void mappingShouldNotContainTypeInformationWhenValueTypeOfMapMatchesDeclaration( assertThat(mappedUpdate).doesNotContainKey("$set.concreteMap.jasnah._class"); } + @Test // GH-4567 + void updateShouldAllowNullValuesInMap() { + + Map map = Collections.singletonMap("jasnah", new NestedDocument("kholin")); + + Update update = new Update().set("concreteMap", Collections.singletonMap("jasnah", null)); + Document mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), + context.getPersistentEntity(EntityWithObjectMap.class)); + + assertThat(mappedUpdate).isEqualTo(new Document("$set", new Document("concreteMap", Collections.singletonMap("jasnah", null)))); + } + @Test // DATAMONGO-1250 @SuppressWarnings("unchecked") void mapsUpdateWithBothReadingAndWritingConverterRegistered() { From d8d5f11b3abbd2926b0ac79d1f173957cd7c7805 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Thu, 7 Dec 2023 09:53:54 +0100 Subject: [PATCH 3/3] Add test to verify map keys retain order when mapped. See: #4577 --- .../core/convert/QueryMapperUnitTests.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java index 88984baa1f..b0d72fd06f 100755 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/QueryMapperUnitTests.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.TreeMap; import org.bson.conversions.Bson; import org.bson.types.Code; @@ -1517,6 +1518,20 @@ void usesKeyNameWithDotsIfFieldNameTypeIsKey() { assertThat(mappedObject).isEqualTo("{ 'field.name.with.dots' : 'A' }"); } + @Test // GH-4577 + void mappingShouldRetainMapKeyOrder() { + + TreeMap sourceMap = new TreeMap<>(Map.of("test1", "123", "test2", "456")); + + org.bson.Document target = mapper.getMappedObject(query(where("simpleMap").is(sourceMap)).getQueryObject(), + context.getPersistentEntity(WithSimpleMap.class)); + assertThat(target.get("simpleMap", Map.class)).containsExactlyEntriesOf(sourceMap); + } + + class WithSimpleMap { + Map simpleMap; + } + class WithDeepArrayNesting { List level0;