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 049aa57e9..045181476 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 @@ -38,6 +38,7 @@ import org.bson.codecs.DecoderContext; import org.bson.conversions.Bson; import org.bson.json.JsonReader; import org.bson.types.ObjectId; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.context.ApplicationContext; @@ -415,8 +416,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App EntityProjection property = returnedTypeDescriptor.findProperty(name); if (property == null) { - return new ConversionContext(sourceConverter, conversions, path, MappingMongoConverter.this::readDocument, collectionConverter, - mapConverter, dbRefConverter, elementConverter); + return new ConversionContext(sourceConverter, conversions, path, MappingMongoConverter.this::readDocument, + collectionConverter, mapConverter, dbRefConverter, elementConverter); } return new ProjectingConversionContext(sourceConverter, conversions, path, collectionConverter, mapConverter, @@ -966,8 +967,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App TypeInformation type = prop.getTypeInformation(); if (conversions.getPropertyValueConversions().hasValueConverter(prop)) { - accessor.put(prop, - conversions.getPropertyValueConversions().getValueConverter(prop).write(obj, new MongoConversionContext(prop, this))); + accessor.put(prop, conversions.getPropertyValueConversions().getValueConverter(prop).write(obj, + new MongoConversionContext(prop, this))); return; } @@ -1302,9 +1303,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App DocumentAccessor accessor = new DocumentAccessor(bson); if (conversions.getPropertyValueConversions().hasValueConverter(property)) { - accessor.put(property, - conversions.getPropertyValueConversions().getValueConverter(property) - .write(value, new MongoConversionContext(property, this))); + accessor.put(property, conversions.getPropertyValueConversions().getValueConverter(property).write(value, + new MongoConversionContext(property, this))); return; } @@ -1971,12 +1971,15 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App return null; } - if (context.conversions.getPropertyValueConversions().hasValueConverter(property)) { - return (T) context.conversions.getPropertyValueConversions().getValueConverter(property).read(value, + CustomConversions conversions = context.conversions; + if (conversions.getPropertyValueConversions().hasValueConverter(property)) { + return (T) conversions.getPropertyValueConversions().getValueConverter(property).read(value, new MongoConversionContext(property, context.sourceConverter)); } - return (T) context.convert(value, property.getTypeInformation()); + ConversionContext contextToUse = context.forProperty(property.getName()); + + return (T) contextToUse.convert(value, property.getTypeInformation()); } public MongoDbPropertyValueProvider withContext(ConversionContext context) { 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 6852cb2cc..4a8602f35 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 @@ -44,6 +44,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; + import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.ConversionNotSupportedException; import org.springframework.beans.factory.annotation.Autowired; @@ -2734,6 +2735,23 @@ class MappingMongoConverterUnitTests { assertThat(projection.getName()).isEqualTo("my-book by Walter White"); } + @Test // GH-4120 + void shouldReadDtoProjection() { + + org.bson.Document author = new org.bson.Document("firstName", "Walter").append("lastName", "White"); + org.bson.Document book = new org.bson.Document("_id", "foo").append("name", "my-book").append("author", author); + + EntityProjectionIntrospector introspector = EntityProjectionIntrospector.create(converter.getProjectionFactory(), + EntityProjectionIntrospector.ProjectionPredicate.typeHierarchy() + .and((target, underlyingType) -> !converter.conversions.isSimpleType(target)), + mappingContext); + + AuthorOnly projection = converter.project(introspector.introspect(AuthorOnly.class, Book.class), book); + + assertThat(projection.getAuthor().getFirstName()).isEqualTo("Walter"); + assertThat(projection.getAuthor().getLastName()).isEqualTo("White"); + } + @Test // GH-3596 void simpleConverter() { @@ -3637,6 +3655,21 @@ class MappingMongoConverterUnitTests { String getName(); } + @lombok.Value + static class AuthorOnly { + + AuthorNameOnly author; + } + + @lombok.Value + static class AuthorNameOnly { + + String firstName; + + String lastName; + + } + @Data static class Book {