Browse Source

Fix `@DocumentReference` resolution for properties used in constructor.

This commit fixes an issue that prevented referenced entities from being used as constructor arguments.

Closes: #3806
Original pull request: #3810.
pull/3821/head
Christoph Strobl 4 years ago committed by Mark Paluch
parent
commit
f128e6df15
No known key found for this signature in database
GPG Key ID: 4406B84C1661DCD1
  1. 25
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverter.java
  2. 106
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateDocumentReferenceTests.java

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

@ -530,7 +530,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
if (conversionService.canConvert(DocumentPointer.class, property.getActualType())) { if (conversionService.canConvert(DocumentPointer.class, property.getActualType())) {
if(value == null) { if (value == null) {
return; return;
} }
@ -541,7 +541,9 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
} else { } else {
accessor.setProperty(property, accessor.setProperty(property,
dbRefResolver.resolveReference(property, new DocumentReferenceSource(documentAccessor.getDocument(), documentAccessor.get(property)), referenceLookupDelegate, context::convert)); dbRefResolver.resolveReference(property,
new DocumentReferenceSource(documentAccessor.getDocument(), documentAccessor.get(property)),
referenceLookupDelegate, context::convert));
} }
return; return;
} }
@ -875,10 +877,12 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
if (property.isAssociation()) { if (property.isAssociation()) {
List<Object> targetCollection = collection.stream().map(it -> { List<Object> targetCollection = collection.stream().map(it -> {
return documentPointerFactory.computePointer(mappingContext, property, it, property.getActualType()).getPointer(); return documentPointerFactory.computePointer(mappingContext, property, it, property.getActualType())
.getPointer();
}).collect(Collectors.toList()); }).collect(Collectors.toList());
return writeCollectionInternal(targetCollection, ClassTypeInformation.from(DocumentPointer.class), new ArrayList<>()); return writeCollectionInternal(targetCollection, ClassTypeInformation.from(DocumentPointer.class),
new ArrayList<>());
} }
if (property.hasExplicitWriteTarget()) { if (property.hasExplicitWriteTarget()) {
@ -931,7 +935,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
if (property.isDbReference()) { if (property.isDbReference()) {
document.put(simpleKey, value != null ? createDBRef(value, property) : null); document.put(simpleKey, value != null ? createDBRef(value, property) : null);
} else { } else {
document.put(simpleKey, documentPointerFactory.computePointer(mappingContext, property, value, property.getActualType()).getPointer()); document.put(simpleKey, documentPointerFactory
.computePointer(mappingContext, property, value, property.getActualType()).getPointer());
} }
} else { } else {
@ -1814,6 +1819,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return (T) dbRefResolver.resolveDbRef(property, dbref, callback, dbRefProxyHandler); return (T) dbRefResolver.resolveDbRef(property, dbref, callback, dbRefProxyHandler);
} }
if (property.isDocumentReference()) {
return (T) dbRefResolver.resolveReference(property, accessor.get(property), referenceLookupDelegate,
context::convert);
}
return super.getPropertyValue(property); return super.getPropertyValue(property);
} }
} }
@ -2036,7 +2046,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
if (typeHint.isMap()) { if (typeHint.isMap()) {
if(ClassUtils.isAssignable(Document.class, typeHint.getType())) { if (ClassUtils.isAssignable(Document.class, typeHint.getType())) {
return (S) documentConverter.convert(this, BsonUtils.asBson(source), typeHint); return (S) documentConverter.convert(this, BsonUtils.asBson(source), typeHint);
} }
@ -2044,7 +2054,8 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
return (S) mapConverter.convert(this, BsonUtils.asBson(source), typeHint); return (S) mapConverter.convert(this, BsonUtils.asBson(source), typeHint);
} }
throw new IllegalArgumentException(String.format("Expected map like structure but found %s", source.getClass())); throw new IllegalArgumentException(
String.format("Expected map like structure but found %s", source.getClass()));
} }
if (source instanceof DBRef) { if (source instanceof DBRef) {

106
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateDocumentReferenceTests.java

@ -733,6 +733,52 @@ public class MongoTemplateDocumentReferenceTests {
assertThat(result.simplePreinitializedValueRef).isEmpty(); assertThat(result.simplePreinitializedValueRef).isEmpty();
} }
@Test // GH-3806
void resolveReferenceWhenUsedAsCtorArgument() {
Publisher publisher = new Publisher();
publisher.id = "p-111";
publisher.name = "ppp";
template.save(publisher);
WithRequiredArgsCtor source = new WithRequiredArgsCtor("id-1", publisher);
template.save(source);
WithRequiredArgsCtor target = template.findOne(query(where("id").is(source.id)), WithRequiredArgsCtor.class);
assertThat(target.publisher).isNotNull();
}
@Test // GH-3806
void resolveLazyReferenceWhenUsedAsCtorArgument() {
Publisher publisher = new Publisher();
publisher.id = "p-111";
publisher.name = "ppp";
template.save(publisher);
WithLazyRequiredArgsCtor source = new WithLazyRequiredArgsCtor("id-1", publisher);
template.save(source);
WithLazyRequiredArgsCtor target = template.findOne(query(where("id").is(source.id)), WithLazyRequiredArgsCtor.class);
// proxy not yet resolved
LazyLoadingTestUtils.assertProxy(target.publisher, (proxy) -> {
assertThat(proxy.isResolved()).isFalse();
assertThat(proxy.currentValue()).isNull();
});
// resolve the proxy by invoking a method on it
assertThat(target.getPublisher().getName()).isEqualTo("ppp");
LazyLoadingTestUtils.assertProxy(target.publisher, (proxy) -> {
assertThat(proxy.isResolved()).isTrue();
});
}
@Test // GH-3602 @Test // GH-3602
void queryForReference() { void queryForReference() {
@ -1371,6 +1417,30 @@ public class MongoTemplateDocumentReferenceTests {
String id; String id;
String acronym; String acronym;
String name; String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAcronym() {
return acronym;
}
public void setAcronym(String acronym) {
this.acronym = acronym;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
} }
@Data @Data
@ -1401,4 +1471,40 @@ public class MongoTemplateDocumentReferenceTests {
@DocumentReference(lookup="{'publisherId':?#{#self._id} }") @DocumentReference(lookup="{'publisherId':?#{#self._id} }")
List<OneToManyStyleBook> books; List<OneToManyStyleBook> books;
} }
static class WithRequiredArgsCtor {
final String id;
@DocumentReference
final Publisher publisher;
public WithRequiredArgsCtor(String id, Publisher publisher) {
this.id = id;
this.publisher = publisher;
}
}
static class WithLazyRequiredArgsCtor {
final String id;
@DocumentReference(lazy = true)
final Publisher publisher;
public WithLazyRequiredArgsCtor(String id, Publisher publisher) {
this.id = id;
this.publisher = publisher;
}
public String getId() {
return id;
}
public Publisher getPublisher() {
return publisher;
}
}
} }

Loading…
Cancel
Save