使用 kotlinx.serialization 库反序列化具有不同值类型的 JSON 数组
Deserialize JSON array with different values type with kotlinx.serialization library
我正在尝试反序列化以下字符串:
val stringJson = "{\"decomposed\":[\", \",{\"id\":4944372,\"name\":\"Johny\",\"various\":false,\"composer\":false,\"genres\":[]}]}"
反序列化适用于以下代码
@Serializable
data class Artist(
val decomposed: JsonArray
)
fun main() {
val jsonString = "{\"decomposed\":[\", \",{\"id\":4944372,\"name\":\"Johny\",\"various\":false,\"composer\":false,\"genres\":[]}]}"
println(Json.decodeFromString<Artist>(jsonString))
}
但我想做类似的事情
@Serializable
class Decomposed {
@Serializable
class DecomposedClassValue(val value: DecomposedClass)
@Serializable
class StringValue(val value: String)
}
@Serializable
data class DecomposedClass(
val id: Long? = null,
val name: String? = null,
val various: Boolean? = null,
val composer: Boolean? = null,
val genres: JsonArray? = null
)
@Serializable
data class Artist(
val decomposed: List<Decomposed>
)
fun main() {
val jsonString = "{\"decomposed\":[\", \",{\"id\":4944372,\"name\":\"Johny\",\"various\":false,\"composer\":false,\"genres\":[]}]}"
println(Json.decodeFromString<Artist>(jsonString))
}
但是 kotlinx.serialization
预计会失败 JsonDecodingException: Unexpected JSON token at offset 15: Expected '{, kind: CLASS'
而且我不知道如何重写我的 Decomposed
所以反序列化工作。你能帮帮我吗?
您正在尝试做的事情叫做 polymorphic deserialization。
要求反序列化的目标classes有一个共同的superclass(最好是sealed):
@Serializable
data class Artist(
val decomposed: List<Decomposed>
)
@Serializable
sealed class Decomposed
@Serializable
class StringValue(val value: String) : Decomposed() //Can't add superclass to String, so we have to create a wrapper class which we could make extend Decomposed
@Serializable
data class DecomposedClass(
val id: Long? = null,
val name: String? = null,
val various: Boolean? = null,
val composer: Boolean? = null,
val genres: JsonArray? = null
) : Decomposed() //DecomposedClassValue is redundant, we may extend DecomposedClass from Decomposed directly
这将允许您反序列化以下格式的 JSON:
val jsonString = "{\"decomposed\":[{\"type\":\"StringValue\", \"value\":\",\"}, {\"type\":\"DecomposedClass\", \"id\":4944372,\"name\":\"Johny\",\"various\":false,\"composer\":false,\"genres\":[]}]}"
由于没有class descriminator in original JSON, serialization library can't determine the actual serializer which should be used to deserialize Kotlin class. You will have to write custom JsonContentPolymorphicSerializer,连线到Decomposed
class;您还必须为 StringValue
class 编写自定义序列化程序,因为它在 JSON 中表示为 String
,而不是带有 [=16] 的 JSON 对象=] String
类型的字段:
object DecomposedSerializer : JsonContentPolymorphicSerializer<Decomposed>(Decomposed::class) {
override fun selectDeserializer(element: JsonElement) = when {
element is JsonPrimitive -> StringValue.serializer()
else -> DecomposedClass.serializer()
}
}
object StringValueSerializer : KSerializer<StringValue> {
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("StringValue")
override fun deserialize(decoder: Decoder): StringValue {
require(decoder is JsonDecoder)
val element = decoder.decodeJsonElement()
return StringValue(element.jsonPrimitive.content)
}
override fun serialize(encoder: Encoder, value: StringValue) {
encoder.encodeString(value.value)
}
}
@Serializable(with = DecomposedSerializer::class)
sealed class Decomposed
@Serializable(with = StringValueSerializer::class)
class StringValue(val value: String) : Decomposed()
这将允许您反序列化 JSON 原始格式。
我正在尝试反序列化以下字符串:
val stringJson = "{\"decomposed\":[\", \",{\"id\":4944372,\"name\":\"Johny\",\"various\":false,\"composer\":false,\"genres\":[]}]}"
反序列化适用于以下代码
@Serializable
data class Artist(
val decomposed: JsonArray
)
fun main() {
val jsonString = "{\"decomposed\":[\", \",{\"id\":4944372,\"name\":\"Johny\",\"various\":false,\"composer\":false,\"genres\":[]}]}"
println(Json.decodeFromString<Artist>(jsonString))
}
但我想做类似的事情
@Serializable
class Decomposed {
@Serializable
class DecomposedClassValue(val value: DecomposedClass)
@Serializable
class StringValue(val value: String)
}
@Serializable
data class DecomposedClass(
val id: Long? = null,
val name: String? = null,
val various: Boolean? = null,
val composer: Boolean? = null,
val genres: JsonArray? = null
)
@Serializable
data class Artist(
val decomposed: List<Decomposed>
)
fun main() {
val jsonString = "{\"decomposed\":[\", \",{\"id\":4944372,\"name\":\"Johny\",\"various\":false,\"composer\":false,\"genres\":[]}]}"
println(Json.decodeFromString<Artist>(jsonString))
}
但是 kotlinx.serialization
预计会失败 JsonDecodingException: Unexpected JSON token at offset 15: Expected '{, kind: CLASS'
而且我不知道如何重写我的 Decomposed
所以反序列化工作。你能帮帮我吗?
您正在尝试做的事情叫做 polymorphic deserialization。 要求反序列化的目标classes有一个共同的superclass(最好是sealed):
@Serializable
data class Artist(
val decomposed: List<Decomposed>
)
@Serializable
sealed class Decomposed
@Serializable
class StringValue(val value: String) : Decomposed() //Can't add superclass to String, so we have to create a wrapper class which we could make extend Decomposed
@Serializable
data class DecomposedClass(
val id: Long? = null,
val name: String? = null,
val various: Boolean? = null,
val composer: Boolean? = null,
val genres: JsonArray? = null
) : Decomposed() //DecomposedClassValue is redundant, we may extend DecomposedClass from Decomposed directly
这将允许您反序列化以下格式的 JSON:
val jsonString = "{\"decomposed\":[{\"type\":\"StringValue\", \"value\":\",\"}, {\"type\":\"DecomposedClass\", \"id\":4944372,\"name\":\"Johny\",\"various\":false,\"composer\":false,\"genres\":[]}]}"
由于没有class descriminator in original JSON, serialization library can't determine the actual serializer which should be used to deserialize Kotlin class. You will have to write custom JsonContentPolymorphicSerializer,连线到Decomposed
class;您还必须为 StringValue
class 编写自定义序列化程序,因为它在 JSON 中表示为 String
,而不是带有 [=16] 的 JSON 对象=] String
类型的字段:
object DecomposedSerializer : JsonContentPolymorphicSerializer<Decomposed>(Decomposed::class) {
override fun selectDeserializer(element: JsonElement) = when {
element is JsonPrimitive -> StringValue.serializer()
else -> DecomposedClass.serializer()
}
}
object StringValueSerializer : KSerializer<StringValue> {
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("StringValue")
override fun deserialize(decoder: Decoder): StringValue {
require(decoder is JsonDecoder)
val element = decoder.decodeJsonElement()
return StringValue(element.jsonPrimitive.content)
}
override fun serialize(encoder: Encoder, value: StringValue) {
encoder.encodeString(value.value)
}
}
@Serializable(with = DecomposedSerializer::class)
sealed class Decomposed
@Serializable(with = StringValueSerializer::class)
class StringValue(val value: String) : Decomposed()
这将允许您反序列化 JSON 原始格式。