Десериализация объекта в класс данных, содержащий делегированные свойства (наследование с делегированием)
Ваш вопрос Я проверил проблемы и документы и не нашел решения.
Следующий код правильно сериализует объект () в строку, но десериализацию из строки обратно в элементы
Component
не работает.
Есть предложения, как это сделать, не удаляя делегации?
Спасибо :)
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)
}
}
Ошибка
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"])
1 ответ
Немного изменил ваш код, чтобы исправить десериализацию, так как он не работал при создании компонента Info из-за того, что его нет в известном списке.
- Поле типа переопределения класса Info
data class Info(
override var id: String,
override val type: String = "info",
) : Component
- Добавить в
JsonSubTypes
аннотация:
@JsonSubTypes(
value = [
Type(value = Space::class, name = Space.TYPE),
Type(value = Command::class, name = Command.TYPE),
Type(value = Info::class, name = "info"),
]
)
interface Component
Также небольшое исправление в тестовом коде:
val before = Command(
value = "text",
component = Info(id = "d")
)
val asString = objectMapper.writeValueAsString(before)
val after = objectMapper.readValue(asString, Component::class.java)
assertThat(after).isEqualTo(before)