From 595a346705ee2be1a77ceb07c0f68d4a47ea413b Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 15 Jul 2021 09:59:46 +0200 Subject: [PATCH] Polishing. Support DBObject and Map that as source for entity materialization and map conversion. See #3702 Original pull request: #3704. --- .../core/convert/MappingMongoConverter.java | 13 +++--- .../data/mongodb/util/BsonUtils.java | 43 +++++++++++++++++++ .../MappingMongoConverterUnitTests.java | 5 ++- .../data/mongodb/util/json/BsonUtilsTest.java | 17 +++++++- 4 files changed, 67 insertions(+), 11 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java index 0f707888d..38ef5dc1a 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java @@ -1909,14 +1909,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App if (typeHint.isMap()) { if(ClassUtils.isAssignable(Document.class, typeHint.getType())) { - return (S) documentConverter.convert(this, (Bson) source, typeHint); + return (S) documentConverter.convert(this, BsonUtils.asBson(source), typeHint); } - if(source instanceof Bson) { - return (S) mapConverter.convert(this, (Bson) source, typeHint); - } - if(source instanceof Map) { - return (S) mapConverter.convert(this, new Document((Map) source), typeHint); + if (BsonUtils.supportsBson(source)) { + return (S) mapConverter.convert(this, BsonUtils.asBson(source), typeHint); } throw new IllegalArgumentException(String.format("Expected map like structure but found %s", source.getClass())); @@ -1931,8 +1928,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App String.format(INCOMPATIBLE_TYPES, source, BasicDBList.class, typeHint.getType(), getPath())); } - if (source instanceof Bson) { - return (S) documentConverter.convert(this, (Bson) source, typeHint); + if (BsonUtils.supportsBson(source)) { + return (S) documentConverter.convert(this, BsonUtils.asBson(source), typeHint); } return (S) elementConverter.convert(source, typeHint); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/BsonUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/BsonUtils.java index f4bd9436e..20d4e1d3c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/BsonUtils.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/BsonUtils.java @@ -488,6 +488,49 @@ public class BsonUtils { return null; } + /** + * Returns the given source object as {@link Bson}, i.e. {@link Document}s and maps as is or throw + * {@link IllegalArgumentException}. + * + * @param source + * @return the converted/casted source object. + * @throws IllegalArgumentException if {@code source} cannot be converted/cast to {@link Bson}. + * @since 3.2.3 + * @see #supportsBson(Object) + */ + @SuppressWarnings("unchecked") + public static Bson asBson(Object source) { + + if (source instanceof Document) { + return (Document) source; + } + + if (source instanceof BasicDBObject) { + return (BasicDBObject) source; + } + + if (source instanceof DBObject) { + return new Document(((DBObject) source).toMap()); + } + + if (source instanceof Map) { + return new Document((Map) source); + } + + throw new IllegalArgumentException(String.format("Cannot convert %s to Bson", source)); + } + + /** + * Returns the given source can be used/converted as {@link Bson}. + * + * @param source + * @return {@literal true} if the given source can be converted to {@link Bson}. + * @since 3.2.3 + */ + public static boolean supportsBson(Object source) { + return source instanceof DBObject || source instanceof Map; + } + /** * Returns given object as {@link Collection}. Will return the {@link Collection} as is if the source is a * {@link Collection} already, will convert an array into a {@link Collection} or simply create a single element 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 a7532b93a..abdc145ed 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 @@ -934,10 +934,11 @@ class MappingMongoConverterUnitTests { assertThat(readResult.iterator().next()).isInstanceOf(Address.class); } - @Test // DATAMONGO-402 + @Test // DATAMONGO-402, GH-3702 void readsMemberClassCorrectly() { - org.bson.Document document = new org.bson.Document("inner", new org.bson.Document("value", "FOO!")); + org.bson.Document document = new org.bson.Document("inner", + new LinkedHashMap<>(new org.bson.Document("value", "FOO!"))); Outer outer = converter.read(Outer.class, document); assertThat(outer.inner).isNotNull(); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/util/json/BsonUtilsTest.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/util/json/BsonUtilsTest.java index 8210dd9a6..166932c23 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/util/json/BsonUtilsTest.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/util/json/BsonUtilsTest.java @@ -19,7 +19,7 @@ import static org.assertj.core.api.Assertions.*; import java.util.ArrayList; import java.util.Collection; -import java.util.List; +import java.util.Collections; import org.bson.BsonDouble; import org.bson.BsonInt32; @@ -29,10 +29,16 @@ import org.bson.BsonString; import org.bson.Document; import org.bson.types.ObjectId; import org.junit.jupiter.api.Test; + import org.springframework.data.mongodb.util.BsonUtils; +import com.mongodb.BasicDBList; + /** + * Unit tests for {@link BsonUtils}. + * * @author Christoph Strobl + * @author Mark Paluch */ class BsonUtilsTest { @@ -111,4 +117,13 @@ class BsonUtilsTest { assertThat((Collection)BsonUtils.asCollection(source)).containsExactly(source); } + + @Test // GH-3702 + void supportsBsonShouldReportIfConversionSupported() { + + assertThat(BsonUtils.supportsBson("foo")).isFalse(); + assertThat(BsonUtils.supportsBson(new Document())).isTrue(); + assertThat(BsonUtils.supportsBson(new BasicDBList())).isTrue(); + assertThat(BsonUtils.supportsBson(Collections.emptyMap())).isTrue(); + } }