Skip to content

NullPointerException thrown for Updates with Maps that contain null values #4567

Closed
@lukasraska

Description

@lukasraska

Hello,
(probably) due to #4555 where QueryMapper.convertSimpleOrDocument was refactored to use Stream collect, it's now not possible to update documents with arbitrary Map that has null values.

It can be replicated with following entity:

@Document
public class TestPojo {
    @Id
    private String id;
    private Map<String, Object> data;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Map<String, Object> getData() {
        return data;
    }

    public void setData(Map<String, Object> data) {
        this.data = data;
    }

and following test case:

public interface TestPojoRepository extends MongoRepository<TestPojo, String> {}

@Test
void testUpdateNullValue() {
    var obj = new TestPojo();
    obj.setData(Collections.singletonMap("test", "value"));
    var saved = pojoRepository.save(obj);

    var query = new Query().addCriteria(Criteria.where("id").is(saved.getId()));
    var upd = new Update().set("data", Collections.singletonMap("test", null));

    mongoTemplate.updateFirst(query, upd, TestPojo.class);
}

which yields following exception:

java.lang.NullPointerException
	at java.base/java.util.Objects.requireNonNull(Objects.java:233)
	at java.base/java.util.stream.Collectors.lambda$uniqKeysMapAccumulator$1(Collectors.java:180)
	at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
	at java.base/java.util.Collections$2.tryAdvance(Collections.java:5073)
	at java.base/java.util.Collections$2.forEachRemaining(Collections.java:5081)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
	at org.springframework.data.mongodb.core.convert.QueryMapper.convertSimpleOrDocument(QueryMapper.java:620)
	at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedValue(QueryMapper.java:525)
	at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObjectForField(QueryMapper.java:351)
	at org.springframework.data.mongodb.core.convert.UpdateMapper.getMappedObjectForField(UpdateMapper.java:160)
	at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObject(QueryMapper.java:170)
	at org.springframework.data.mongodb.core.convert.UpdateMapper.getMappedObject(UpdateMapper.java:66)
	at org.springframework.data.mongodb.core.convert.QueryMapper.convertSimpleOrDocument(QueryMapper.java:603)
	at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedKeyword(QueryMapper.java:410)
	at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObject(QueryMapper.java:129)
	at org.springframework.data.mongodb.core.convert.UpdateMapper.getMappedObject(UpdateMapper.java:66)
	at org.springframework.data.mongodb.core.QueryOperations$UpdateContext.getMappedUpdate(QueryOperations.java:895)
	at org.springframework.data.mongodb.core.MongoTemplate.doUpdate(MongoTemplate.java:1720)
	at org.springframework.data.mongodb.core.MongoTemplate.updateFirst(MongoTemplate.java:1643)
	at com.example.demo.DemoApplicationTests.testUpdateNullValue(DemoApplicationTests.java:36)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)

Which is caused by this known "bug" within Stream implementation - https://bugs.openjdk.org/browse/JDK-8148463

Is there any plan to either revert the refactor to the previous implementation logic or rewrite it from scratch in a way where it will support null values? I'm willing to create PR + write relevant test cases if I get suggestion what would be the suggested fix.

Thanks

Metadata

Metadata

Labels

type: regressionA regression from a previous release

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions