Skip to content

Commit f128e6d

Browse files
christophstroblmp911de
authored andcommitted
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.
1 parent 270456e commit f128e6d

File tree

2 files changed

+124
-7
lines changed

2 files changed

+124
-7
lines changed

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

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ private void readAssociation(Association<MongoPersistentProperty> association, P
530530

531531
if (conversionService.canConvert(DocumentPointer.class, property.getActualType())) {
532532

533-
if(value == null) {
533+
if (value == null) {
534534
return;
535535
}
536536

@@ -541,7 +541,9 @@ private void readAssociation(Association<MongoPersistentProperty> association, P
541541
} else {
542542

543543
accessor.setProperty(property,
544-
dbRefResolver.resolveReference(property, new DocumentReferenceSource(documentAccessor.getDocument(), documentAccessor.get(property)), referenceLookupDelegate, context::convert));
544+
dbRefResolver.resolveReference(property,
545+
new DocumentReferenceSource(documentAccessor.getDocument(), documentAccessor.get(property)),
546+
referenceLookupDelegate, context::convert));
545547
}
546548
return;
547549
}
@@ -875,10 +877,12 @@ protected List<Object> createCollection(Collection<?> collection, MongoPersisten
875877
if (property.isAssociation()) {
876878

877879
List<Object> targetCollection = collection.stream().map(it -> {
878-
return documentPointerFactory.computePointer(mappingContext, property, it, property.getActualType()).getPointer();
880+
return documentPointerFactory.computePointer(mappingContext, property, it, property.getActualType())
881+
.getPointer();
879882
}).collect(Collectors.toList());
880883

881-
return writeCollectionInternal(targetCollection, ClassTypeInformation.from(DocumentPointer.class), new ArrayList<>());
884+
return writeCollectionInternal(targetCollection, ClassTypeInformation.from(DocumentPointer.class),
885+
new ArrayList<>());
882886
}
883887

884888
if (property.hasExplicitWriteTarget()) {
@@ -931,7 +935,8 @@ protected Bson createMap(Map<Object, Object> map, MongoPersistentProperty proper
931935
if (property.isDbReference()) {
932936
document.put(simpleKey, value != null ? createDBRef(value, property) : null);
933937
} else {
934-
document.put(simpleKey, documentPointerFactory.computePointer(mappingContext, property, value, property.getActualType()).getPointer());
938+
document.put(simpleKey, documentPointerFactory
939+
.computePointer(mappingContext, property, value, property.getActualType()).getPointer());
935940
}
936941

937942
} else {
@@ -1814,6 +1819,11 @@ public <T> T getPropertyValue(MongoPersistentProperty property) {
18141819
return (T) dbRefResolver.resolveDbRef(property, dbref, callback, dbRefProxyHandler);
18151820
}
18161821

1822+
if (property.isDocumentReference()) {
1823+
return (T) dbRefResolver.resolveReference(property, accessor.get(property), referenceLookupDelegate,
1824+
context::convert);
1825+
}
1826+
18171827
return super.getPropertyValue(property);
18181828
}
18191829
}
@@ -2036,15 +2046,16 @@ public <S extends Object> S convert(Object source, TypeInformation<? extends S>
20362046

20372047
if (typeHint.isMap()) {
20382048

2039-
if(ClassUtils.isAssignable(Document.class, typeHint.getType())) {
2049+
if (ClassUtils.isAssignable(Document.class, typeHint.getType())) {
20402050
return (S) documentConverter.convert(this, BsonUtils.asBson(source), typeHint);
20412051
}
20422052

20432053
if (BsonUtils.supportsBson(source)) {
20442054
return (S) mapConverter.convert(this, BsonUtils.asBson(source), typeHint);
20452055
}
20462056

2047-
throw new IllegalArgumentException(String.format("Expected map like structure but found %s", source.getClass()));
2057+
throw new IllegalArgumentException(
2058+
String.format("Expected map like structure but found %s", source.getClass()));
20482059
}
20492060

20502061
if (source instanceof DBRef) {

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

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,52 @@ void loadNoExistingCollectionReference() {
733733
assertThat(result.simplePreinitializedValueRef).isEmpty();
734734
}
735735

736+
@Test // GH-3806
737+
void resolveReferenceWhenUsedAsCtorArgument() {
738+
739+
Publisher publisher = new Publisher();
740+
publisher.id = "p-111";
741+
publisher.name = "ppp";
742+
743+
template.save(publisher);
744+
745+
WithRequiredArgsCtor source = new WithRequiredArgsCtor("id-1", publisher);
746+
747+
template.save(source);
748+
749+
WithRequiredArgsCtor target = template.findOne(query(where("id").is(source.id)), WithRequiredArgsCtor.class);
750+
assertThat(target.publisher).isNotNull();
751+
}
752+
753+
@Test // GH-3806
754+
void resolveLazyReferenceWhenUsedAsCtorArgument() {
755+
756+
Publisher publisher = new Publisher();
757+
publisher.id = "p-111";
758+
publisher.name = "ppp";
759+
760+
template.save(publisher);
761+
762+
WithLazyRequiredArgsCtor source = new WithLazyRequiredArgsCtor("id-1", publisher);
763+
764+
template.save(source);
765+
766+
WithLazyRequiredArgsCtor target = template.findOne(query(where("id").is(source.id)), WithLazyRequiredArgsCtor.class);
767+
768+
// proxy not yet resolved
769+
LazyLoadingTestUtils.assertProxy(target.publisher, (proxy) -> {
770+
771+
assertThat(proxy.isResolved()).isFalse();
772+
assertThat(proxy.currentValue()).isNull();
773+
});
774+
775+
// resolve the proxy by invoking a method on it
776+
assertThat(target.getPublisher().getName()).isEqualTo("ppp");
777+
LazyLoadingTestUtils.assertProxy(target.publisher, (proxy) -> {
778+
assertThat(proxy.isResolved()).isTrue();
779+
});
780+
}
781+
736782
@Test // GH-3602
737783
void queryForReference() {
738784

@@ -1371,6 +1417,30 @@ static class Publisher {
13711417
String id;
13721418
String acronym;
13731419
String name;
1420+
1421+
public String getId() {
1422+
return id;
1423+
}
1424+
1425+
public void setId(String id) {
1426+
this.id = id;
1427+
}
1428+
1429+
public String getAcronym() {
1430+
return acronym;
1431+
}
1432+
1433+
public void setAcronym(String acronym) {
1434+
this.acronym = acronym;
1435+
}
1436+
1437+
public String getName() {
1438+
return name;
1439+
}
1440+
1441+
public void setName(String name) {
1442+
this.name = name;
1443+
}
13741444
}
13751445

13761446
@Data
@@ -1401,4 +1471,40 @@ static class OneToManyStylePublisher {
14011471
@DocumentReference(lookup="{'publisherId':?#{#self._id} }")
14021472
List<OneToManyStyleBook> books;
14031473
}
1474+
1475+
static class WithRequiredArgsCtor {
1476+
1477+
final String id;
1478+
1479+
@DocumentReference
1480+
final Publisher publisher;
1481+
1482+
public WithRequiredArgsCtor(String id, Publisher publisher) {
1483+
1484+
this.id = id;
1485+
this.publisher = publisher;
1486+
}
1487+
}
1488+
1489+
static class WithLazyRequiredArgsCtor {
1490+
1491+
final String id;
1492+
1493+
@DocumentReference(lazy = true)
1494+
final Publisher publisher;
1495+
1496+
public WithLazyRequiredArgsCtor(String id, Publisher publisher) {
1497+
1498+
this.id = id;
1499+
this.publisher = publisher;
1500+
}
1501+
1502+
public String getId() {
1503+
return id;
1504+
}
1505+
1506+
public Publisher getPublisher() {
1507+
return publisher;
1508+
}
1509+
}
14041510
}

0 commit comments

Comments
 (0)