diff --git a/pom.xml b/pom.xml index 828f56af2e..649330214d 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-3580-SNAPSHOT pom Spring Data MongoDB diff --git a/spring-data-mongodb-benchmarks/pom.xml b/spring-data-mongodb-benchmarks/pom.xml index f0fbb601c8..dad8f373c9 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-3580-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml index 1a17321782..a29a7de9ac 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-3580-SNAPSHOT ../pom.xml diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml index 0248517caf..3ddebab990 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-3580-SNAPSHOT ../pom.xml 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 33586de368..8cc823a0b8 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 @@ -292,7 +292,7 @@ protected S readDocument(ConversionContext context, Bson bson Class rawType = typeToRead.getType(); if (conversions.hasCustomReadTarget(bson.getClass(), rawType)) { - return doConvert(bson, rawType); + return doConvert(bson, rawType, typeHint.getType()); } if (Document.class.isAssignableFrom(rawType)) { @@ -1532,9 +1532,17 @@ public MappingMongoConverter with(MongoDatabaseFactory dbFactory) { return target; } + private T doConvert(Object value, Class target) { + return doConvert(value, target, null); + } + @SuppressWarnings("ConstantConditions") - private T doConvert(Object value, Class target) { - return conversionService.convert(value, target); + private T doConvert(Object value, Class target, @Nullable Class fallback) { + + if(conversionService.canConvert(value.getClass(), target) || fallback == null) { + return conversionService.convert(value, target); + } + return conversionService.convert(value, fallback); } /** 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 ffad28b231..db3a4e1b19 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 @@ -2383,6 +2383,51 @@ void writeEmbeddedTypeWithComplexValue() { .doesNotContainKey("address.city"); } + @Test // GH-3580 + void shouldFallbackToConfiguredCustomConversionTargetOnRead() { + + GenericTypeConverter genericTypeConverter = spy(new GenericTypeConverter()); + + converter = new MappingMongoConverter(resolver, mappingContext); + converter.setCustomConversions(MongoCustomConversions.create(it -> { + it.registerConverter(genericTypeConverter); + })); + converter.afterPropertiesSet(); + + org.bson.Document source = new org.bson.Document("_class", SubTypeOfGenericType.class.getName()).append("value", + "v1"); + GenericType target = converter.read(GenericType.class, source); + + assertThat(target).isInstanceOf(GenericType.class); + assertThat(target.content).isEqualTo("v1"); + + verify(genericTypeConverter).convert(eq(source)); + } + + @Test // GH-3580 + void shouldUseMostConcreteCustomConversionTargetOnRead() { + + GenericTypeConverter genericTypeConverter = spy(new GenericTypeConverter()); + SubTypeOfGenericTypeConverter subTypeOfGenericTypeConverter = spy(new SubTypeOfGenericTypeConverter()); + + converter = new MappingMongoConverter(resolver, mappingContext); + converter.setCustomConversions(MongoCustomConversions.create(it -> { + it.registerConverter(genericTypeConverter); + it.registerConverter(subTypeOfGenericTypeConverter); + })); + converter.afterPropertiesSet(); + + org.bson.Document source = new org.bson.Document("_class", SubTypeOfGenericType.class.getName()).append("value", + "v1"); + GenericType target = converter.read(GenericType.class, source); + + assertThat(target).isInstanceOf(SubTypeOfGenericType.class); + assertThat(target.content).isEqualTo("v1_s"); + + verify(genericTypeConverter, never()).convert(any()); + verify(subTypeOfGenericTypeConverter).convert(eq(source)); + } + static class GenericType { T content; } @@ -2899,4 +2944,31 @@ public Person onAfterConvert(Person entity, org.bson.Document document, String c } } + static class SubTypeOfGenericType extends GenericType { + + } + + @ReadingConverter + static class GenericTypeConverter implements Converter> { + + @Override + public GenericType convert(org.bson.Document source) { + + GenericType target = new GenericType<>(); + target.content = source.get("value"); + return target; + } + } + + @ReadingConverter + static class SubTypeOfGenericTypeConverter implements Converter { + + @Override + public SubTypeOfGenericType convert(org.bson.Document source) { + + SubTypeOfGenericType target = new SubTypeOfGenericType(); + target.content = source.getString("value") + "_s"; + return target; + } + } }