Skip to content

Custom deserializer via @JsonDeserialize should be invoked before NULL-checking #4225

@MartinHaeusler

Description

@MartinHaeusler

Search before asking

  • I searched in the issues and found nothing similar.

Describe the bug

When specifying a custom deserializer via @JsonDeserialize, the deserializer should be invoked before the value is checked for null. It is entirely possible that the custom deserializer produces a non-null object out of a JSON null value. Currently this doesn't seem to be possible.

To Reproduce

class MyClass(
    @JsonDeserialize(using = CustomListDeserializer::class)
    val myList: List<String>
)

// the following is a minimal implementation to demonstrate the point;
// for the sake of argument, assume that the deserializer contains further complex custom logic.
class CustomListDeserializer : JsonDeserializer<List<String>>() {

    override fun deserialize(p: JsonParser, ctxt: DeserializationContext): List<Any> {

        val jsonToken = p.currentToken

        return when (jsonToken) {
            JsonToken.VALUE_NULL -> {
                emptyList()
            }
            JsonToken.VALUE_STRING -> {
                listOf(p.valueAsString)
            }
            else -> {
                throw JsonParseException(p, "Failed to parse value!")
            }
        }
    }

}

... and try to deserialize the following JSON:

{
    "myList": null
}

This will result in a MissingKotlinParameterException, claiming that: value failed for JSON property myList due to missing (therefore NULL) value for creator parameter myList which is a non-nullable type

Expected behavior

I would expect that the JSON is deserialized by invoking the CustomListDeserializer on the JSON null value, producing an empty list. This empty list should then be handed to the primary constructor of MyClass.

Versions

Kotlin: 1.9.20
Jackson-module-kotlin: 2.15.3
Jackson-databind: 2.15.3

Additional context

No response

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