Beloo
Beloo

Reputation: 9925

Support deserialization of inheritance chained objects in kotlin with jackson

Assume we need to comply deserialization of such object inheritance structure:

open class Parent(
    @JsonProperty("parent_value")
    val parentValue: String = "default"
)

class Child(
    @JsonProperty("child_value")
    val childValue: String) : Parent()

Both parent & child object define own fields and @JsonProperty over it.

Also i have a test to check deserialization:

@Test
fun testDeserializeWithInheritance() {

    val map = mapOf("child_value" to "success", "parent_value" to "success")

    val jsonResult = objectMapper.writerWithDefaultPrettyPrinter()
        .writeValueAsString(map)

    println("serialized object: $jsonResult")

    val deserialized: JsonConverterModuleTest.Child = objectMapper.readValue(jsonResult)
    println("deserialized object: withdraw=${deserialized.childValue} parentValue = ${deserialized.parentValue}, exchangeFrom = ${deserialized.parentValue}")

    assertEquals("success", deserialized.childValue)
    assertEquals("success", deserialized.parentValue)
}

But a problem is the test fails with error:

serialized object: { "child_value" : "success", "parent_value" : "success" }

org.junit.ComparisonFailure: parent value not equal:
Expected:success
Actual :default

How to deserialize the child object properly? The main goal is to not duplicate fields nor @JsonProperty annotations in child class.

I have a solution for the issue, but open to accept better one

Upvotes: 0

Views: 1300

Answers (1)

Beloo
Beloo

Reputation: 9925

The issue happens because annotation over constructor field is not applied to field nor getter automatically (kotlin mechanizm). Also Seems that it is not processed on deserialization of a child object.
Jackson supports annotations over field or over getter methods, so an appropriate solutions are either

open class Parent(
    @get:JsonProperty("parent_value")
    val parentValue: String = "default"
)

or

open class Parent(
    @field:JsonProperty("parent_value")
    val parentValue: String = "default"
)

With this the test completes

Upvotes: 2

Related Questions