Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mutliple level of @JsonTypeInfo and @JsonSubTypes does not work #831

Open
3 tasks done
osigida opened this issue Sep 23, 2024 · 3 comments
Open
3 tasks done

Mutliple level of @JsonTypeInfo and @JsonSubTypes does not work #831

osigida opened this issue Sep 23, 2024 · 3 comments
Labels

Comments

@osigida
Copy link

osigida commented Sep 23, 2024

Search before asking

  • I searched in the issues and found nothing similar.
  • I searched in the issues of databind and other modules used and found nothing similar.
  • I have confirmed that the problem only occurs when using Kotlin.

Describe the bug

Multi layer hierarchy could not be deserialized and fails with an error like the following

Cannot construct instance of `com.test.B2` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information

To Reproduce

package com.test
import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test

class JacksonKotlinModuleIssue {
    private val mapper = jacksonObjectMapper()

    @Test
    fun `Hierarchy deserialization test`() {
        val c1 = C1()
        val c2 = C2()
        val c3 = C3()
        val c4 = C4()

        val c1Json = mapper.writeValueAsString(c1)
        val c2Json = mapper.writeValueAsString(c2)
        val c3Json = mapper.writeValueAsString(c3)
        val c4Json = mapper.writeValueAsString(c4)

        // works
        val c1deserialised = mapper.readValue(c1Json, C1::class.java)
        // works
        val c2deserialised = mapper.readValue(c2Json, B1::class.java)
        // works
        val c3deserialised = mapper.readValue(c3Json, B2::class.java)
        // fails
        val c4deserialised = mapper.readValue(c4Json, A::class.java)

        assertEquals(c1, c1deserialised)
        assertEquals(c2, c2deserialised)
        assertEquals(c3, c3deserialised)
        assertEquals(c4, c4deserialised)
    }
}

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.EXISTING_PROPERTY,
    property = "type",
    visible = true,
)
@JsonSubTypes(
    JsonSubTypes.Type(value = B1::class, name = "B1"),
    JsonSubTypes.Type(value = B2::class, name = "B2"),
)
sealed class A {
    abstract val type: String
}

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.EXISTING_PROPERTY,
    property = "subtype",
    visible = true,
)
@JsonSubTypes(
    JsonSubTypes.Type(value = C1::class, name = "C1"),
    JsonSubTypes.Type(value = C2::class, name = "C2"),
)
sealed class B1(
    override val type: String = "B1",
) : A() {
    abstract val subtype: String
}

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.EXISTING_PROPERTY,
    property = "subtype",
    visible = true,
)
@JsonSubTypes(
    JsonSubTypes.Type(value = C3::class, name = "C3"),
    JsonSubTypes.Type(value = C4::class, name = "C4"),
)
sealed class B2(
    override val type: String = "B2",
) : A() {
    abstract val subtype: String
}

data class C1(
    override val subtype: String = "C1",
) : B1()

data class C2(
    override val subtype: String = "C2",
) : B1()

data class C3(
    override val subtype: String = "C3",
) : B2()

data class C4(
    override val subtype: String = "C4",
) : B2()

Expected behavior

deserialisation works fine for multi-layer hierarchy

Versions

Kotlin: 1.9
Jackson-module-kotlin: 2.17.2
Jackson-databind: 2.17.2

Additional context

No response

@osigida osigida added the bug label Sep 23, 2024
@cowtowncoder
Copy link
Member

Correct: multiple levels with differing @JsonTypeInfo is not supported by jackson-databind.
Since feature itself is not provided by Kotlin module so issue would need to be in jackson-databind (there likely already is an open issue).

There are no current plans to support such feature, fwtw.

@osigida
Copy link
Author

osigida commented Sep 24, 2024

Hi @cowtowncoder! Thanks a lot for the reply!
Could you please share the issue? I tried to find anything related to the problem but found very little information.

@cowtowncoder
Copy link
Member

I think #2957 is what I had in mind -- not sure how close a match it is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants