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

Polymorphic sealed class missing type information #765

Open
MaxDaten opened this issue Feb 7, 2024 · 0 comments
Open

Polymorphic sealed class missing type information #765

MaxDaten opened this issue Feb 7, 2024 · 0 comments
Labels

Comments

@MaxDaten
Copy link

MaxDaten commented Feb 7, 2024

Your question

Hi,

maybe I'm missing some important piece or my thinking is a bit too naïve, but I try to write a generic message passing library based on a json protocol.

package com.fasterxml.jackson.module.kotlin.test.github

import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.exc.MismatchedInputException
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import junit.framework.TestCase.assertEquals
import org.junit.Assert.assertThrows
import kotlin.test.Test

class ReproductionTest {

    @JsonTypeInfo(use = JsonTypeInfo.Id.SIMPLE_NAME, include = JsonTypeInfo.As.PROPERTY, property = "@type")
    sealed class Response<out Err, out B>{
        data class Success<out B>(val response: B) : Response<Nothing, B>()
        data class Failure<out Err>(val error: Err) : Response<Err, Nothing>()
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.SIMPLE_NAME, include = JsonTypeInfo.As.PROPERTY, property = "@type")
    sealed class Message {
        data class Text(val text: String) : Message()
        data class Image(val url: String) : Message()
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.SIMPLE_NAME, include = JsonTypeInfo.As.PROPERTY, property = "@type")
    sealed class Error {
        data class NotFound(val message: String) : Error()
        data class BadRequest(val message: String) : Error()
    }

    val asJson = """{"@type":"Success","response":{"@type":"Text","text":"foo"}}"""
    val responseSuccess: Response<Error, Message> = Response.Success(Message.Text("foo"))

    @Test
    fun testReadAsValue() {
        val mapper = jacksonObjectMapper()
        val refType = mapper.typeFactory.constructParametricType(Response::class.java, Error::class.java, Message::class.java)

        // Failing com.fasterxml.jackson.databind.exc.InvalidTypeIdException:
        // Could not resolve type id 'Success' as a subtype of ...
        assertEquals(
            responseSuccess,
            mapper.readValue<Response<Error, Message>>(asJson, refType)
        )
    }

    @Test
    fun testWriteAsValue() {
        val mapper = jacksonObjectMapper()

        // Failing
        assertEquals(
            asJson,
            mapper.writeValueAsString(responseSuccess) // actual: {"@type":"Success","response":{"text":"foo"}}
        )
    }
}

My expectations/goals would be:

  1. if defined at the root type of Err/B type information should be included in the "response": {...} value and should be in control of the consuming code side (Message & Error would be defined there). But the type information is missing the the serialized value
  2. and of course it should be deserializable

Is that possible to achieve? I tried various variations, including mapper.writerFor(refType), without any success.

Help is appreciated!

Greetings

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

1 participant