使用 kotlin 序列化将 JSON 反序列化为 "non-stable" 值
Deserialize JSON with "non-stable" values using kotlin serialization
我没有很好地从 BE 结构化 JSON(我无法更改),它以前是用 moshi(针对该问题的自定义适配器)处理的。现在我正在尝试使用纯 kotlin 序列化,但如前所述,JSON 结构对我帮助不大。
{
"foo": {
"version":1,
"mask": [
{
"values": [
{ "bar": 1, ... }
]
},
{
"values": [
"important text i guess"
]
},
]
}
}
现在你可以看到我的问题是 values 可以同时包含 object 和 string。所有这些都应该解析成 kotlin,其中 values 看起来像这样:
data class Values(
val bar: Int? = null,
val text: String? = null,
...
)
理论上我可以改变本地实现,例如拆分 values class 之类的。
我已经尝试应用多态反序列化,但据我了解,如果 JSON 中没有设置 class 鉴别器,它无法识别 values 的两个后代之间的差异.
有什么好的建议吗?
更新
我试过的多态版本(以防我刚刚犯了一些错误)
@Polymorphic
@Serializable
sealed class Values{
@Serializable
data class ObjectValues(
val bar: Int? = null,
...
)
@Serializable
data class TextValues(
val text: String? = null
)
}
并使用它:
Json {
ignoreUnknownKeys = true
serializersModule = SerializersModule {
polymorphic(Values::class) {
subclass(Values.ObjectValues::class, Values.ObjectValues.serializer())
subclass(Values.TextValues::class, Values.TextValues.serializer())
}
}
错误:
Polymorphic serializer was not found for missing class discriminator ('null')
JSON input: {"bar":42,...}
免责声明
我知道这会解决所有问题:)
"values": [ { "text":"important text i guess" } ]
classDiscriminator
不是多态反序列化的强制要求。在这种情况下,您可以使用 content-based polymorphic deserialization。
您只需要为 Values
class 定义一个 JsonContentPolymorphicSerializer
,并使用一些逻辑来精确选择子 class 序列化器:
object ValuesSerializer : JsonContentPolymorphicSerializer<Values>(Values::class) {
override fun selectDeserializer(element: JsonElement) = when {
element.jsonObject["values"]!!.jsonArray.first() is JsonObject -> ObjectValues.serializer()
else -> TextValues.serializer()
}
}
并将其连接为 Values
class:
的序列化程序
@Serializable(with = ValuesSerializer::class)
sealed class Values
@Serializable
data class TextValues(val values: List<String>) : Values()
@Serializable
data class ObjectValues(val values: List<Bar>) : Values()
@Serializable
data class Bar(val bar: Int)
@Serializable
data class MyJson(val foo: Foo)
@Serializable
data class Foo(val version: Int, val mask: List<Values>)
不需要serializersModule
:
val result = Json.decodeFromString<MyJson>(json)
我没有很好地从 BE 结构化 JSON(我无法更改),它以前是用 moshi(针对该问题的自定义适配器)处理的。现在我正在尝试使用纯 kotlin 序列化,但如前所述,JSON 结构对我帮助不大。
{
"foo": {
"version":1,
"mask": [
{
"values": [
{ "bar": 1, ... }
]
},
{
"values": [
"important text i guess"
]
},
]
}
}
现在你可以看到我的问题是 values 可以同时包含 object 和 string。所有这些都应该解析成 kotlin,其中 values 看起来像这样:
data class Values(
val bar: Int? = null,
val text: String? = null,
...
)
理论上我可以改变本地实现,例如拆分 values class 之类的。 我已经尝试应用多态反序列化,但据我了解,如果 JSON 中没有设置 class 鉴别器,它无法识别 values 的两个后代之间的差异.
有什么好的建议吗?
更新
我试过的多态版本(以防我刚刚犯了一些错误)
@Polymorphic
@Serializable
sealed class Values{
@Serializable
data class ObjectValues(
val bar: Int? = null,
...
)
@Serializable
data class TextValues(
val text: String? = null
)
}
并使用它:
Json {
ignoreUnknownKeys = true
serializersModule = SerializersModule {
polymorphic(Values::class) {
subclass(Values.ObjectValues::class, Values.ObjectValues.serializer())
subclass(Values.TextValues::class, Values.TextValues.serializer())
}
}
错误:
Polymorphic serializer was not found for missing class discriminator ('null')
JSON input: {"bar":42,...}
免责声明 我知道这会解决所有问题:)
"values": [ { "text":"important text i guess" } ]
classDiscriminator
不是多态反序列化的强制要求。在这种情况下,您可以使用 content-based polymorphic deserialization。
您只需要为 Values
class 定义一个 JsonContentPolymorphicSerializer
,并使用一些逻辑来精确选择子 class 序列化器:
object ValuesSerializer : JsonContentPolymorphicSerializer<Values>(Values::class) {
override fun selectDeserializer(element: JsonElement) = when {
element.jsonObject["values"]!!.jsonArray.first() is JsonObject -> ObjectValues.serializer()
else -> TextValues.serializer()
}
}
并将其连接为 Values
class:
@Serializable(with = ValuesSerializer::class)
sealed class Values
@Serializable
data class TextValues(val values: List<String>) : Values()
@Serializable
data class ObjectValues(val values: List<Bar>) : Values()
@Serializable
data class Bar(val bar: Int)
@Serializable
data class MyJson(val foo: Foo)
@Serializable
data class Foo(val version: Int, val mask: List<Values>)
不需要serializersModule
:
val result = Json.decodeFromString<MyJson>(json)