Skip to content

Deserializing object to data class that contains delegated properties (inheritance with delegation)  #471

@pnuckowski

Description

@pnuckowski

Your question
I have checked issues and docs and could not find solution.

The follwing code properly serialize object (Component) to string, but deserialization from string back to insgtances of Component doesn't work.

Any suggestions how to do it, without removing delegations?

Thanks :)

import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonSubTypes.Type
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.fasterxml.jackson.core.json.JsonReadFeature
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "type"
)
@JsonSubTypes(
    value = [
        Type(value = Space::class, name = Space.TYPE),
        Type(value = Command::class, name = Command.TYPE),
    ]
)
interface Component {
    var id: String

    @get:JsonIgnore
    val type: String
}

data class Command(
    val value: String,
    val component: Component
) : Component by component {
    override val type: String
        get() = TYPE

    companion object {
        const val TYPE = "command"
    }
}

data class Space(
    val space: String,
    private val component: Component
) : Component by component {
    override val type: String
        get() = TYPE

    companion object {
        const val TYPE = "space"
    }
}

data class Info(
    override var id: String,
    override val type: String = "",
) : Component

class FooTest {
    //    private val objectMapper = ObjectMapperFactory.createObjectMapper(emptyList())
    private val objectMapper = JsonMapper.builder()
        .addModule(KotlinModule())
        .serializationInclusion(JsonInclude.Include.NON_NULL)
        .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
        .enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT)
        .enable(JsonReadFeature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER)
        .build()

    @Test
    fun `should deserialize`() {

        val value = objectMapper.writeValueAsString(
            Command(
                value = "text",
                component = Info(id = "d")
            )
        )

        val obj = objectMapper.readValue(value, Component::class.java)
        assertThat(value).isEqualTo(obj)
    }
}

Error


com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'Info' as a subtype of `<>.<>.<>.<>.jackson.Component`: known type ids = [command, space] (for POJO property 'component')
 at [Source: (String)"{"type":"command","value":"text","component":{"type":"Info","id":"d"},"id":"d"}"; line: 1, column: 54] (through reference chain: <>.<>.<>.<>.jackson.Command["component"])

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions