spring-data-mongodb icon indicating copy to clipboard operation
spring-data-mongodb copied to clipboard

Document with Map decorated with @NonNull and @DocumentReference fails to deserialize

Open bamapookie opened this issue 3 months ago • 4 comments

Given the following class:

package org.example.mongoemptymaptest.model;

import lombok.Builder;
import lombok.Data;
import lombok.NonNull;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.DocumentReference;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Data
@Builder
@Document(collection = "parent_documents")
public class ParentDocument {

    @Id
    @Builder.Default
    UUID id = UUID.randomUUID();

    @NonNull
    @Builder.Default
    @DBRef
    Map<String, ChildDocument> dbRefChildren = new HashMap<>();

    @NonNull
    @Builder.Default
    @DBRef(lazy = true)
    Map<String, ChildDocument> lazyDbRefChildren = new HashMap<>();

    @NonNull
    @Builder.Default
    @DocumentReference
    Map<String, ChildDocument> documentReferenceChildren = new HashMap<>();

    @NonNull
    @Builder.Default
    @DocumentReference(lazy = true)
    Map<String, ChildDocument> lazyDocumentReferenceChildren = new HashMap<>();
}

The document will fail to deserialize if documentReferenceChildren is an empty map, and will fail to properly resolve the map for lazyDocumentReferenceChildren if it is an empty map. In that case, getLazyDocumentReferenceChildren().values() method will return null.

Unit tests illustrating the bug: https://github.com/bamapookie/MongoEmptyMapTest

bamapookie avatar Oct 03 '25 21:10 bamapookie

That's an interesting one since the map is empty in the db. So the ReferenceLookupDelegate needs to check on the property type for better insight into what to return instead of just indicating there's no value by returning null via readReference

christophstrobl avatar Oct 06 '25 14:10 christophstrobl

Is there any problem with the @DocumentReference referring to the values of the map, and not the map itself? I wasn't sure if there was a way to annotate just the values of the map. The map itself should be persisted with the parent document, and only the child documents should be referenced via the @DocumentReference.

bamapookie avatar Oct 06 '25 15:10 bamapookie

It looks like at https://github.com/spring-projects/spring-data-mongodb/blob/ef83581733b627c37d26528286e3ba6cb2c0b0cd/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ReferenceLookupDelegate.java#L132 we should check for property.isCollectionLike() before returning an empty list, or checking for property.isMap() before returning an empty document or empty map.

Alternately, at https://github.com/spring-projects/spring-data-mongodb/blob/ef83581733b627c37d26528286e3ba6cb2c0b0cd/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/convert/ReferenceLookupDelegate.java#L119, we should have a check for property.isMap() and handling the map case before returning null.

bamapookie avatar Oct 06 '25 17:10 bamapookie

PR here: https://github.com/spring-projects/spring-data-mongodb/pull/5066

bamapookie avatar Oct 06 '25 23:10 bamapookie