IS1_SO
IS1_SO

Reputation: 1045

How to control null deserialization with default values and required values in Jackson with Kotlin?

Using Jackson 2.9.6

I have the following data class definition:

data class SomeDTO @JsonCreator internal constructor
(
    @get:JsonProperty(value = "first-property", required = true)
    @param:JsonProperty(value = "first-property", required = true)
    val firstProperty: Long?,

    @get:JsonProperty(value = "second-property")
    @param:JsonProperty(value = "second-property")
    val secondProperty: Int = 1234

    @get:JsonProperty("third-property", required = true)
    @param:JsonProperty("third-property", required = true)
    val thirdProperty: Int
)

What I expect for a JSON that deserializes into SomeDTO

  1. If firstProperty is missing, it should throw an exception.
  2. If firstProperty is null, it should assign null since it is nullable.
  3. If secondProperty is missing or null it should assign the default value of 1234
  4. If thirdProperty is missing or null, it should throw an exception.

Basically that I can control which values can be deserialized and into what.

What I am experiencing:

If not using KotlinModule then (1), (2), and (4) work but (3) fails with:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot map null into type int (set DeserializationConfig.DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES to 'false' to allow)

If using KotlinModule then (2), (3), and (4) work but (1) fails.

Main part of ObjectMapper configuration:

disable(
        MapperFeature.AUTO_DETECT_CREATORS,
        MapperFeature.AUTO_DETECT_FIELDS,
        MapperFeature.AUTO_DETECT_GETTERS,
        MapperFeature.AUTO_DETECT_IS_GETTERS
       )
disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)

registerModule(ParanamerModule())
registerModule(KotlinModule()) // Might be registered or not

disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
enable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)

I think it is easier to use the KotlinModule but I don't know how to tell it to not auto assign null values to nullable fields when the property is missing in the JSON

Upvotes: 2

Views: 4059

Answers (2)

jaco0646
jaco0646

Reputation: 17066

Updating the Kotlin module to version 2.9.7 produces an exception when firstProperty is missing. I've tested it repeatedly, going back and forth between 2.9.6 and 2.9.7 with the code and configuration copied from the OP.

A bug fix in 2.9.7 matches the unexpected behavior described in the OP.

Fixes #168 where JsonProperty(required=true) was being ignored and overridden by nullability check

https://github.com/FasterXML/jackson-module-kotlin/issues/168

Upvotes: 2

Willi Mentzel
Willi Mentzel

Reputation: 29844

This should do what you want:

data class SomeDTO(
        @JsonProperty(value = "first-property", required = true)
        val firstProperty: Long?,

        @JsonProperty(value = "second-property")
        val secondProperty: Int = 1234,

        @JsonProperty("third-property", required = true)
        val thirdProperty: Int
)

A few notes:

1. Since you are using the primary constructor for your annotated fields, in Kotlin you don't need the @JsonCreator annotation.

This is what the GitHub page of the Jackson project says:

By default, Jackson tries to use the "default" constructor (one that takes no arguments), when creating value instances. But you can also choose to use another constructor, or a static factory method to create instance. To do this, you will need to use annotation @JsonCreator, and possibly @JsonProperty annotations to bind names to arguments

  1. You dont need the separate @get and @param annotations. @JsonProperty alone is sufficient for your use-case.

Upvotes: 1

Related Questions