diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ReferenceLookupDelegate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ReferenceLookupDelegate.java index a2726e633..dbbdbe99e 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ReferenceLookupDelegate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ReferenceLookupDelegate.java @@ -62,6 +62,8 @@ import com.mongodb.client.MongoCollection; */ public final class ReferenceLookupDelegate { + private static final Document NO_RESULTS_PREDICATE = new Document("_id", new Document("$exists", false)); + private final MappingContext, MongoPersistentProperty> mappingContext; private final SpELContext spELContext; private final ParameterBindingDocumentCodec codec; @@ -262,25 +264,32 @@ public final class ReferenceLookupDelegate { sort); } - List ors = new ArrayList<>(); - for (Object entry : (Collection) value) { + Collection objects = (Collection) value; + + if (objects.isEmpty()) { + return new ListDocumentReferenceQuery(NO_RESULTS_PREDICATE, sort); + } + + List ors = new ArrayList<>(objects.size()); + for (Object entry : objects) { Document decoded = codec.decode(lookup, bindingContext(property, entry, spELContext)); ors.add(decoded); } - if(ors.isEmpty()) { - return new ListDocumentReferenceQuery(new Document("_id", new Document("$exists", false)), sort); - } - return new ListDocumentReferenceQuery(new Document("$or", ors), sort); } if (property.isMap() && value instanceof Map) { - Map filterMap = new LinkedHashMap<>(); + Set> entries = ((Map) value).entrySet(); + if (entries.isEmpty()) { + return new MapDocumentReferenceQuery(NO_RESULTS_PREDICATE, sort, Collections.emptyMap()); + } - for (Entry entry : ((Map) value).entrySet()) { + Map filterMap = new LinkedHashMap<>(entries.size()); + + for (Entry entry : entries) { Document decoded = codec.decode(lookup, bindingContext(property, entry.getValue(), spELContext)); filterMap.put(entry.getKey(), decoded); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateDocumentReferenceTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateDocumentReferenceTests.java index 2b96b3dc2..c63e7a111 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateDocumentReferenceTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateDocumentReferenceTests.java @@ -698,6 +698,24 @@ public class MongoTemplateDocumentReferenceTests { assertThat(result.simplePreinitializedValueRef).isEmpty(); } + @Test // GH-3805 + void loadEmptyMapReference() { + + String rootCollectionName = template.getCollectionName(CollectionRefRoot.class); + + // an empty reference array. + Document source = new Document("_id", "id-1").append("value", "v1").append("simplePreinitializedMapRef", + new Document()); + + template.execute(db -> { + db.getCollection(rootCollectionName).insertOne(source); + return null; + }); + + CollectionRefRoot result = template.findOne(query(where("id").is("id-1")), CollectionRefRoot.class); + assertThat(result.simplePreinitializedMapRef).isEmpty(); + } + @Test // GH-3805 void loadNoExistingCollectionReference() { @@ -1167,6 +1185,9 @@ public class MongoTemplateDocumentReferenceTests { @DocumentReference(lookup = "{ '_id' : '?#{#target}' }") // Map mapValueRef; + @DocumentReference // + Map simplePreinitializedMapRef = new LinkedHashMap<>(); + @Field("simple-value-ref-annotated-field-name") // @DocumentReference(lookup = "{ '_id' : '?#{#target}' }") // List simpleValueRefWithAnnotatedFieldName;