Skip to content

Optional<JsonNode> deserialization from "absent" value does not work in the expected way #250

@mloho

Description

@mloho

Example:

public record MyRecord(
        Optional<JsonNode> myField
) {
}

When deserialized from: {}
Expected:
myField.isPresent() == false
Actual:
myField.isPresent() == true

This is because myField gets set to an Optional of a NullNode

After spending some time looking into the source code of both the jackson-databind and the jackson-datatype-jdk8 libraries, the problem seems to lie in the OptionalDeserializer (or higher).

During deserialization, when a property is missing, the PropertyValueBuffer::_findMissing method is called and in it, this piece of code is called:
https://github.com/FasterXML/jackson-databind/blob/0fe97e0d69b7d5362907b094d5b979bc2216dc4a/src/main/java/com/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer.java#L203

            // Third: NullValueProvider? (22-Sep-2019, [databind#2458])
            // 08-Aug-2021, tatu: consider [databind#3214]; not null but "absent" value...
            Object absentValue = prop.getNullValueProvider().getAbsentValue(_context);
            if (absentValue != null) {
                return absentValue;
            }

The OptionalDeserializer is not overriding its inherited getAbsentValue method to return Optional.ofNullable(_valueDeserializer.getAbsentValue(ctxt)); (or similar).

Due to the lack of the overriding, the inherited getAbsentValue method actually calls getNullValue instead as can be seen here:
https://github.com/FasterXML/jackson-databind/blob/0fe97e0d69b7d5362907b094d5b979bc2216dc4a/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java#L349

    @Override
    public Object getAbsentValue(DeserializationContext ctxt) throws JsonMappingException {
        return getNullValue(ctxt);
    }

In the case of a JsonNode, the JsonNodeDeserializer is used. This deserializer overrides the getNullValue method to return a NullNode.

https://github.com/FasterXML/jackson-databind/blob/0fe97e0d69b7d5362907b094d5b979bc2216dc4a/src/main/java/com/fasterxml/jackson/databind/deser/std/JsonNodeDeserializer.java#L73

    @Override
    public JsonNode getNullValue(DeserializationContext ctxt) {
        return ctxt.getNodeFactory().nullNode();
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions