Browse Source

Fix DTO projection instantiation.

We now correctly instantiate DTO projection classes by using the actual constructor argument type. Previously, we did not update the conversion context to fetch the correct type but used the type of the DTO projection class instead of the constructor argument.

Closes #4120
pull/4125/head
Mark Paluch 3 years ago
parent
commit
52886e1680
No known key found for this signature in database
GPG Key ID: 4406B84C1661DCD1
  1. 23
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
  2. 33
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterUnitTests.java

23
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java

@ -38,6 +38,7 @@ import org.bson.codecs.DecoderContext; @@ -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 @@ -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 @@ -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 @@ -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 @@ -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) {

33
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; @@ -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 { @@ -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 { @@ -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 {

Loading…
Cancel
Save