diff --git a/pom.xml b/pom.xml
index 366786fc6d..3ef61861eb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-mongodb-parent
- 4.2.0-SNAPSHOT
+ 4.2.0-GH-4491-SNAPSHOT
pom
Spring Data MongoDB
diff --git a/spring-data-mongodb-benchmarks/pom.xml b/spring-data-mongodb-benchmarks/pom.xml
index 2de4b6b635..4cf395104a 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
- 4.2.0-SNAPSHOT
+ 4.2.0-GH-4491-SNAPSHOT
../pom.xml
diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml
index 060a6d0dd9..e41d524181 100644
--- a/spring-data-mongodb-distribution/pom.xml
+++ b/spring-data-mongodb-distribution/pom.xml
@@ -15,7 +15,7 @@
org.springframework.data
spring-data-mongodb-parent
- 4.2.0-SNAPSHOT
+ 4.2.0-GH-4491-SNAPSHOT
../pom.xml
diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml
index dc07f13ccc..ef508ed175 100644
--- a/spring-data-mongodb/pom.xml
+++ b/spring-data-mongodb/pom.xml
@@ -13,7 +13,7 @@
org.springframework.data
spring-data-mongodb-parent
- 4.2.0-SNAPSHOT
+ 4.2.0-GH-4491-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 6aeb08e240..ec5d866461 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
@@ -17,7 +17,16 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -41,7 +50,13 @@
import org.springframework.data.annotation.Reference;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.convert.TypeMapper;
-import org.springframework.data.mapping.*;
+import org.springframework.data.mapping.Association;
+import org.springframework.data.mapping.InstanceCreatorMetadata;
+import org.springframework.data.mapping.MappingException;
+import org.springframework.data.mapping.Parameter;
+import org.springframework.data.mapping.PersistentEntity;
+import org.springframework.data.mapping.PersistentProperty;
+import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.callback.EntityCallbacks;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
@@ -492,7 +507,6 @@ private S read(ConversionContext context, MongoPersistentEntity entity, D
S instance = instantiator.createInstance(entity, provider);
if (entity.requiresPropertyPopulation()) {
-
return populateProperties(context, entity, documentAccessor, evaluator, instance);
}
@@ -571,14 +585,18 @@ private void readProperties(ConversionContext context, MongoPersistentEntity>
ConversionContext propertyContext = context.forProperty(prop);
MongoDbPropertyValueProvider valueProviderToUse = valueProvider.withContext(propertyContext);
- if (prop.isAssociation() && !entity.isCreatorArgument(prop)) {
+ if (prop.isAssociation()) {
if (callback == null) {
callback = getDbRefResolverCallback(propertyContext, documentAccessor, evaluator);
}
- readAssociation(prop.getRequiredAssociation(), accessor, documentAccessor, dbRefProxyHandler, callback,
- propertyContext, evaluator);
+ Object value = readAssociation(prop.getRequiredAssociation(), documentAccessor, dbRefProxyHandler, callback,
+ propertyContext);
+
+ if (value != null) {
+ accessor.setProperty(prop, value);
+ }
continue;
}
@@ -593,17 +611,6 @@ private void readProperties(ConversionContext context, MongoPersistentEntity>
continue;
}
- if (prop.isAssociation()) {
-
- if (callback == null) {
- callback = getDbRefResolverCallback(propertyContext, documentAccessor, evaluator);
- }
-
- readAssociation(prop.getRequiredAssociation(), accessor, documentAccessor, dbRefProxyHandler, callback,
- propertyContext, evaluator);
- continue;
- }
-
accessor.setProperty(prop, valueProviderToUse.getPropertyValue(prop));
}
}
@@ -615,9 +622,10 @@ private DbRefResolverCallback getDbRefResolverCallback(ConversionContext context
(prop, bson, e, path) -> MappingMongoConverter.this.getValueInternal(context, prop, bson, e));
}
- private void readAssociation(Association association, PersistentPropertyAccessor> accessor,
+ @Nullable
+ private Object readAssociation(Association association,
DocumentAccessor documentAccessor, DbRefProxyHandler handler, DbRefResolverCallback callback,
- ConversionContext context, SpELExpressionEvaluator evaluator) {
+ ConversionContext context) {
MongoPersistentProperty property = association.getInverse();
Object value = documentAccessor.get(property);
@@ -630,30 +638,27 @@ private void readAssociation(Association association, P
if (conversionService.canConvert(DocumentPointer.class, property.getActualType())) {
if (value == null) {
- return;
+ return null;
}
DocumentPointer> pointer = () -> value;
// collection like special treatment
- accessor.setProperty(property, conversionService.convert(pointer, property.getActualType()));
+ return conversionService.convert(pointer, property.getActualType());
} else {
- accessor.setProperty(property,
- dbRefResolver.resolveReference(property,
+ return dbRefResolver.resolveReference(property,
new DocumentReferenceSource(documentAccessor.getDocument(), documentAccessor.get(property)),
- referenceLookupDelegate, context.forProperty(property)::convert));
+ referenceLookupDelegate, context.forProperty(property)::convert);
}
- return;
}
if (value == null) {
- return;
+ return null;
}
if (value instanceof DBRef dbref) {
- accessor.setProperty(property, dbRefResolver.resolveDbRef(property, dbref, callback, handler));
- return;
+ return dbRefResolver.resolveDbRef(property, dbref, callback, handler);
}
/*
@@ -664,18 +669,18 @@ private void readAssociation(Association association, P
if (value instanceof Document document) {
if (property.isMap()) {
if (document.isEmpty() || peek(document.values()) instanceof DBRef) {
- accessor.setProperty(property, dbRefResolver.resolveDbRef(property, null, callback, handler));
+ return dbRefResolver.resolveDbRef(property, null, callback, handler);
} else {
- accessor.setProperty(property, readMap(context, document, property.getTypeInformation()));
+ return readMap(context, document, property.getTypeInformation());
}
} else {
- accessor.setProperty(property, read(property.getActualType(), document));
+ return read(property.getActualType(), document);
}
} else if (value instanceof Collection> collection && !collection.isEmpty()
&& peek(collection) instanceof Document) {
- accessor.setProperty(property, readCollectionOrArray(context, collection, property.getTypeInformation()));
+ return readCollectionOrArray(context, collection, property.getTypeInformation());
} else {
- accessor.setProperty(property, dbRefResolver.resolveDbRef(property, null, callback, handler));
+ return dbRefResolver.resolveDbRef(property, null, callback, handler);
}
}
@@ -1961,25 +1966,26 @@ class AssociationAwareMongoDbPropertyValueProvider extends MongoDbPropertyValueP
@SuppressWarnings("unchecked")
public T getPropertyValue(MongoPersistentProperty property) {
- if (property.isDbReference() && property.getDBRef().lazy()) {
+ ConversionContext propertyContext = context.forProperty(property);
- Object rawRefValue = accessor.get(property);
- if (rawRefValue == null) {
- return null;
- }
+ if (property.isAssociation()) {
DbRefResolverCallback callback = new DefaultDbRefResolverCallback(accessor.getDocument(), context.getPath(),
evaluator, (prop, bson, evaluator, path) -> MappingMongoConverter.this.getValueInternal(context, prop, bson,
evaluator));
- DBRef dbref = rawRefValue instanceof DBRef dbRef ? dbRef : null;
- return (T) dbRefResolver.resolveDbRef(property, dbref, callback, dbRefProxyHandler);
+ return (T) readAssociation(property.getRequiredAssociation(), accessor, dbRefProxyHandler, callback,
+ propertyContext);
+ }
+
+ if (property.isUnwrapped()) {
+
+ return (T) readUnwrapped(propertyContext, accessor, property,
+ mappingContext.getRequiredPersistentEntity(property));
}
- if (property.isDocumentReference()) {
- return (T) dbRefResolver.resolveReference(property,
- new DocumentReferenceSource(accessor.getDocument(), accessor.get(property)),
- referenceLookupDelegate, context::convert);
+ if (!accessor.hasValue(property)) {
+ return null;
}
return super.getPropertyValue(property);
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 8a3fac7797..a1eabc33ba 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
@@ -2346,6 +2346,24 @@ void readUnwrappedTypeWithComplexValue() {
.isEqualTo(expected);
}
+ @Test // GH-4491
+ void readUnwrappedTypeWithComplexValueUsingConstructor() {
+
+ org.bson.Document source = new org.bson.Document("_id", "id-1").append("stringValue", "hello").append("address",
+ new org.bson.Document("s", "1007 Mountain Drive").append("city", "Gotham"));
+
+ WithUnwrappedConstructor target = converter.read(WithUnwrappedConstructor.class, source);
+
+ Address expected = new Address();
+ expected.city = "Gotham";
+ expected.street = "1007 Mountain Drive";
+
+ assertThat(target.embeddableValue.stringValue) //
+ .isEqualTo("hello");
+ assertThat(target.embeddableValue.address) //
+ .isEqualTo(expected);
+ }
+
@Test // DATAMONGO-1902
void writeUnwrappedTypeWithComplexValue() {
@@ -3422,6 +3440,18 @@ static class WithNullableUnwrapped {
@Unwrapped.Nullable EmbeddableType embeddableValue;
}
+ static class WithUnwrappedConstructor {
+
+ private final String id;
+
+ private final @Unwrapped.Empty EmbeddableType embeddableValue;
+
+ public WithUnwrappedConstructor(String id, EmbeddableType embeddableValue) {
+ this.id = id;
+ this.embeddableValue = embeddableValue;
+ }
+ }
+
static class WithPrefixedNullableUnwrapped {
String id;
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/encryption/AbstractEncryptionTestBase.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/encryption/AbstractEncryptionTestBase.java
index 393a0d12f2..87f3009cbe 100644
--- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/encryption/AbstractEncryptionTestBase.java
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/encryption/AbstractEncryptionTestBase.java
@@ -353,7 +353,7 @@ void altKeyDetection(@Autowired CachingMongoClientEncryption mongoClientEncrypti
template.save(p3);
template.execute(Person.class, collection -> {
- collection.find(new Document()).forEach(it -> System.out.println(it.toJson()));
+ collection.find(new Document());
return null;
});