Skip to content

Allow reading already resolved DBRef values. #4323

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-SNAPSHOT</version>
<version>4.1.x-GH-4312-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data MongoDB</name>
Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-benchmarks/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-SNAPSHOT</version>
<version>4.1.x-GH-4312-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-SNAPSHOT</version>
<version>4.1.x-GH-4312-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.1.0-SNAPSHOT</version>
<version>4.1.x-GH-4312-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -668,9 +668,32 @@ private void readAssociation(Association<MongoPersistentProperty> association, P
return;
}

DBRef dbref = value instanceof DBRef ? (DBRef) value : null;
if (value instanceof DBRef dbref) {
accessor.setProperty(property, dbRefResolver.resolveDbRef(property, dbref, callback, handler));
return;
}

accessor.setProperty(property, dbRefResolver.resolveDbRef(property, dbref, callback, handler));
/*
* The value might be a pre resolved full document (eg. resulting from an aggregation $lookup).
* In this case we try to map that object to the target type without an additional step ($dbref resolution server roundtrip)
* in between.
*/
if (value instanceof Document document) {
if(property.isMap()) {
if(document.isEmpty() || document.values().iterator().next() instanceof DBRef) {
accessor.setProperty(property, dbRefResolver.resolveDbRef(property, null, callback, handler));
} else {
accessor.setProperty(property, readMap(context, document, property.getTypeInformation()));
}
} else {
accessor.setProperty(property, read(property.getActualType(), document));
}
} else if (value instanceof Collection<?> collection && collection.size() > 0
&& collection.iterator().next() instanceof Document) {
accessor.setProperty(property, readCollectionOrArray(context, collection, property.getTypeInformation()));
} else {
accessor.setProperty(property, dbRefResolver.resolveDbRef(property, null, callback, handler));
}
}

@Nullable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import org.bson.Document;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -110,6 +111,98 @@ void resolvesLazyDBRefOnAccess() {
verify(dbRefResolver).bulkFetch(any());
}

@Test // GH-4312
void conversionShouldAllowReadingAlreadyResolvedReferences() {

Document sampleSource = new Document("_id", "sample-1").append("value", "one");
Document source = new Document("_id", "id-1").append("sample", sampleSource);

WithSingleValueDbRef read = converter.read(WithSingleValueDbRef.class, source);

assertThat(read.sample).isEqualTo(converter.read(Sample.class, sampleSource));
verifyNoInteractions(dbRefResolver);
}

@Test // GH-4312
void conversionShouldAllowReadingAlreadyResolvedListOfReferences() {

Document sample1Source = new Document("_id", "sample-1").append("value", "one");
Document sample2Source = new Document("_id", "sample-2").append("value", "two");
Document source = new Document("_id", "id-1").append("lazyList", List.of(sample1Source, sample2Source));

WithLazyDBRef read = converter.read(WithLazyDBRef.class, source);

assertThat(read.lazyList).containsExactly(converter.read(Sample.class, sample1Source),
converter.read(Sample.class, sample2Source));
verifyNoInteractions(dbRefResolver);
}

@Test // GH-4312
void conversionShouldAllowReadingAlreadyResolvedMapOfReferences() {

Document sample1Source = new Document("_id", "sample-1").append("value", "one");
Document sample2Source = new Document("_id", "sample-2").append("value", "two");
Document source = new Document("_id", "id-1").append("sampleMap",
new Document("s1", sample1Source).append("s2", sample2Source));

WithMapValueDbRef read = converter.read(WithMapValueDbRef.class, source);

assertThat(read.sampleMap) //
.containsEntry("s1", converter.read(Sample.class, sample1Source)) //
.containsEntry("s2", converter.read(Sample.class, sample2Source));
verifyNoInteractions(dbRefResolver);
}

@Test // GH-4312
void conversionShouldAllowReadingAlreadyResolvedMapOfLazyReferences() {

Document sample1Source = new Document("_id", "sample-1").append("value", "one");
Document sample2Source = new Document("_id", "sample-2").append("value", "two");
Document source = new Document("_id", "id-1").append("sampleMapLazy",
new Document("s1", sample1Source).append("s2", sample2Source));

WithMapValueDbRef read = converter.read(WithMapValueDbRef.class, source);

assertThat(read.sampleMapLazy) //
.containsEntry("s1", converter.read(Sample.class, sample1Source)) //
.containsEntry("s2", converter.read(Sample.class, sample2Source));
verifyNoInteractions(dbRefResolver);
}

@Test // GH-4312
void resolvesLazyDBRefMapOnAccess() {

client.getDatabase(DATABASE).getCollection("samples")
.insertMany(Arrays.asList(new Document("_id", "sample-1").append("value", "one"),
new Document("_id", "sample-2").append("value", "two")));

Document source = new Document("_id", "id-1").append("sampleMapLazy",
new Document("s1", new com.mongodb.DBRef("samples", "sample-1")).append("s2",
new com.mongodb.DBRef("samples", "sample-2")));

WithMapValueDbRef target = converter.read(WithMapValueDbRef.class, source);

verify(dbRefResolver).resolveDbRef(any(), isNull(), any(), any());

assertThat(target.sampleMapLazy).isInstanceOf(LazyLoadingProxy.class);
assertThat(target.getSampleMapLazy()).containsEntry("s1", new Sample("sample-1", "one")).containsEntry("s2",
new Sample("sample-2", "two"));

verify(dbRefResolver).bulkFetch(any());
}

@Test // GH-4312
void conversionShouldAllowReadingAlreadyResolvedLazyReferences() {

Document sampleSource = new Document("_id", "sample-1").append("value", "one");
Document source = new Document("_id", "id-1").append("sampleLazy", sampleSource);

WithSingleValueDbRef read = converter.read(WithSingleValueDbRef.class, source);

assertThat(read.sampleLazy).isEqualTo(converter.read(Sample.class, sampleSource));
verifyNoInteractions(dbRefResolver);
}

@Test // DATAMONGO-2004
void resolvesLazyDBRefConstructorArgOnAccess() {

Expand Down Expand Up @@ -164,6 +257,31 @@ List<Sample> getLazyList() {
}
}

@Data
public static class WithSingleValueDbRef {

@Id //
String id;

@DBRef //
Sample sample;

@DBRef(lazy = true) //
Sample sampleLazy;
}

@Data
public static class WithMapValueDbRef {

@Id String id;

@DBRef //
Map<String, Sample> sampleMap;

@DBRef(lazy = true) //
Map<String, Sample> sampleMapLazy;
}

public static class WithLazyDBRefAsConstructorArg {

@Id String id;
Expand Down