From 05727c59fe311b71c503db19f9ebd96c8ca52e86 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Mon, 8 Feb 2021 10:19:51 +0100 Subject: [PATCH 1/4] 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 10c1adf1bf..c44e2991da 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-mongodb-parent - 3.2.0-SNAPSHOT + 3.2.0-GH-3546-SNAPSHOT pom Spring Data MongoDB diff --git a/spring-data-mongodb-benchmarks/pom.xml b/spring-data-mongodb-benchmarks/pom.xml index f0fbb601c8..dcb07d01c3 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 - 3.2.0-SNAPSHOT + 3.2.0-GH-3546-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml index 1a17321782..2aada8b5f6 100644 --- a/spring-data-mongodb-distribution/pom.xml +++ b/spring-data-mongodb-distribution/pom.xml @@ -14,7 +14,7 @@ org.springframework.data spring-data-mongodb-parent - 3.2.0-SNAPSHOT + 3.2.0-GH-3546-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 0248517caf..523afe36ad 100644 --- a/spring-data-mongodb/pom.xml +++ b/spring-data-mongodb/pom.xml @@ -11,7 +11,7 @@ org.springframework.data spring-data-mongodb-parent - 3.2.0-SNAPSHOT + 3.2.0-GH-3546-SNAPSHOT ../pom.xml From 5ea78b5b048a97dddf1404f6dcbb82a9c5da633c Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Mon, 8 Feb 2021 12:33:18 +0100 Subject: [PATCH 2/4] Fix DocumentToStringConverter UUID representation when calling toJson. This commit makes sure to use an Encoder having UuidRepresentation set when calling org.bson.Document#toJson, preventing CodecConfigurationException from being raised. Future versions will make sure the UUID string representation matches the Java default one. --- .../data/mongodb/core/convert/MongoConverters.java | 12 ++++++++++-- .../core/convert/MappingMongoConverterUnitTests.java | 9 +++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java index 7e4b37cd83..70f8fa732b 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java @@ -32,6 +32,9 @@ import org.bson.BsonTimestamp; import org.bson.Document; +import org.bson.UuidRepresentation; +import org.bson.codecs.Codec; +import org.bson.internal.CodecRegistryHelper; import org.bson.types.Binary; import org.bson.types.Code; import org.bson.types.Decimal128; @@ -45,11 +48,12 @@ import org.springframework.data.convert.WritingConverter; import org.springframework.data.mongodb.core.query.Term; import org.springframework.data.mongodb.core.script.NamedMongoScript; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.NumberUtils; import org.springframework.util.StringUtils; +import com.mongodb.MongoClientSettings; + /** * Wrapper class to contain useful converters for the usage with Mongo. * @@ -236,9 +240,13 @@ enum DocumentToStringConverter implements Converter { INSTANCE; + private final Codec codec = CodecRegistryHelper + .createRegistry(MongoClientSettings.getDefaultCodecRegistry(), UuidRepresentation.JAVA_LEGACY) + .get(Document.class); + @Override public String convert(Document source) { - return source.toJson(); + return source.toJson(codec); } } 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 fdaf46692d..f7c516117c 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 @@ -2179,6 +2179,15 @@ public void readAndConvertDBRefNestedByMapCorrectly() { assertThat(((LinkedHashMap) result.get("cluster")).get("_id")).isEqualTo(100L); } + @Test // GH-3546 + void readFlattensNestedDocumentToStringIfNecessary() { + + org.bson.Document source = new org.bson.Document("street", new org.bson.Document("json", "string").append("_id", UUID.randomUUID())); + + Address target = converter.read(Address.class, source); + assertThat(target.street).isNotNull(); + } + static class GenericType { T content; } From fd8c89b2895669136ed4f274ac4c5cf0950ad0e9 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Mon, 8 Feb 2021 15:47:38 +0100 Subject: [PATCH 3/4] Use UUID toString representation when converting org.bson.Document into a json String. This commit switches the rendering of UUID values to their toString format when printing org.bson.Document to json via the DocumentToString converter. This will move the resulting representation from {"$binary": "QUK3ZihZ9cdhWjTf5TZqrw==", "$type": "03"} to 480971b0-7160-4120-acd0-6fd6b82418ad which is the more natural variant within Java applications. The conversion only applies on read in cases where an entire document eg. a composite id, is mapped to a String property of the domain model. --- .../mongodb/core/convert/MongoConverters.java | 28 +++++++++++++++---- .../convert/MongoConvertersUnitTests.java | 11 +++++++- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java index 70f8fa732b..1ab8bb6276 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java @@ -27,14 +27,18 @@ import java.util.Collection; import java.util.Currency; import java.util.List; +import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import org.bson.BsonReader; import org.bson.BsonTimestamp; +import org.bson.BsonWriter; import org.bson.Document; -import org.bson.UuidRepresentation; import org.bson.codecs.Codec; -import org.bson.internal.CodecRegistryHelper; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.EncoderContext; +import org.bson.codecs.configuration.CodecRegistries; import org.bson.types.Binary; import org.bson.types.Code; import org.bson.types.Decimal128; @@ -240,9 +244,23 @@ enum DocumentToStringConverter implements Converter { INSTANCE; - private final Codec codec = CodecRegistryHelper - .createRegistry(MongoClientSettings.getDefaultCodecRegistry(), UuidRepresentation.JAVA_LEGACY) - .get(Document.class); + private final Codec codec = CodecRegistries.fromRegistries(CodecRegistries.fromCodecs(new Codec() { + + @Override + public void encode(BsonWriter writer, UUID value, EncoderContext encoderContext) { + writer.writeString(value.toString()); + } + + @Override + public Class getEncoderClass() { + return UUID.class; + } + + @Override + public UUID decode(BsonReader reader, DecoderContext decoderContext) { + throw new IllegalStateException("decode not supported"); + } + }), MongoClientSettings.getDefaultCodecRegistry()).get(Document.class); @Override public String convert(Document source) { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoConvertersUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoConvertersUnitTests.java index 7e9c7323f7..88cf3314dd 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoConvertersUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MongoConvertersUnitTests.java @@ -22,6 +22,7 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Currency; +import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -29,7 +30,6 @@ import org.bson.BsonTimestamp; import org.bson.Document; import org.junit.jupiter.api.Test; - import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.data.geo.Box; @@ -42,6 +42,7 @@ import org.springframework.data.mongodb.core.convert.MongoConverters.BigDecimalToStringConverter; import org.springframework.data.mongodb.core.convert.MongoConverters.BsonTimestampToInstantConverter; import org.springframework.data.mongodb.core.convert.MongoConverters.CurrencyToStringConverter; +import org.springframework.data.mongodb.core.convert.MongoConverters.DocumentToStringConverter; import org.springframework.data.mongodb.core.convert.MongoConverters.IntegerToAtomicIntegerConverter; import org.springframework.data.mongodb.core.convert.MongoConverters.LongToAtomicLongConverter; import org.springframework.data.mongodb.core.convert.MongoConverters.StringToBigDecimalConverter; @@ -173,4 +174,12 @@ public void convertsUrisToString() { assertThat(conversionService.convert(URI.create("/segment"), String.class)).isEqualTo("/segment"); assertThat(conversionService.convert("/segment", URI.class)).isEqualTo(URI.create("/segment")); } + + @Test // GH-3546 + void convertsDocumentWithUUidToString() { + + UUID uuid = UUID.randomUUID(); + assertThat(DocumentToStringConverter.INSTANCE.convert(new Document("_id", uuid))) + .isEqualTo("{\"_id\": \"" + uuid.toString() + "\"}"); + } } From 34fbcae54fd0d7ab0a0d6926f871200f1c51f993 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Mon, 8 Feb 2021 16:18:10 +0100 Subject: [PATCH 4/4] Polishing Reduce method visibility in tests, enable missed test and format code. --- .../mongodb/core/convert/MongoConverters.java | 2 +- .../MappingMongoConverterUnitTests.java | 5 ++-- .../convert/MongoConvertersUnitTests.java | 30 +++++++++---------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java index 1ab8bb6276..efc1c1a2e4 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MongoConverters.java @@ -294,7 +294,7 @@ enum DocumentToNamedMongoScriptConverter implements Converter