Mert Elifoğlu
Mert Elifoğlu

Reputation: 101

Deserializing non-null type by passing a default value in Kotlin

I want to deserialize a non-null field in a request model using custom deserializer in Kotlin like this:

import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.deser.std.StdDeserializer

data class MyRequest(val foo: Foo) {

    data class Foo(val bar: String)

    companion object {
        object Deserializer : StdDeserializer<Foo>(Foo::class.java) { //This is added to Jackson Module successfully somewhere else
            override fun deserialize(jsonParser: JsonParser?, context: DeserializationContext?): Foo {
                val node: JsonNode = jsonParser!!.codec.readTree(jsonParser)
                return if (node.isNull || node.isTextual.not()) Foo("default")
                else Foo(node.asText())
            }
        }
    }
}

But when I send a post request with empty json body, I get this:

[org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Instantiation of [simple type, class com.me.myapi.model.request.MyRequest] value failed for JSON property foo due to missing (therefore NULL) value for creator parameter foo which is a non-nullable type; nested exception is com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException

Since Foo is a non-null type and I did not pass anything in request body for foo, this is being thrown before deserialization. I wonder if there is a way to handle this exception, such as giving a default value and continue with deserialization step.

Upvotes: 2

Views: 2489

Answers (2)

Mert Elifoğlu
Mert Elifoğlu

Reputation: 101

I have achieved this simply by overriding getNullValue() method of the deserializer:

object Deserializer : StdDeserializer<Foo>(Foo::class.java) {
    override fun deserialize(jsonParser: JsonParser?, context: DeserializationContext?): Foo {
        val node: JsonNode = jsonParser!!.codec.readTree(jsonParser)
        return if (node.isNull || node.isTextual.not()) Foo("default")
        else Foo(node.asText())
    }

    override fun getNullValue(): Foo {
        return Foo("default value")
    }
}

Upvotes: 1

k.wahome
k.wahome

Reputation: 1062

With version 2.10.0 of jackson-databind you can have:

data class MyDataClass (
    @JsonSetter(nulls = Nulls.SKIP)
    val defaultParameter:String="some default value",
)

Also, with version 2.8.4 or above of jackson-kotlin-module you can do:

val mapper: ObjectMapper = ObjectMapper().registerModule(KotlinModule()) // "inform" Jackson about Kotlin

...

data class MyDataClass(
    val defaultParameter:String="some default value",
)

Upvotes: 4

Related Questions