FasterXML / FasterXML/jackson-module-kotlin

Polymorphic sealed class missing type information

Open
#765 0 comments 0 reactions 0 assignees View on GitHub
question
Dominant language
Kotlin
Stars
1.2k
Forks
187
Avg merge
9h 48m
Merged PRs (30d)
16

Description

### 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.

```kotlin
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{
data class Success(val response: B) : Response()
data class Failure(val error: Err) : Response()
}

@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 = 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>(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

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.