gpt4 book ai didi

json - List 类的自定义 KotlinX 序列化程序

转载 作者:行者123 更新时间:2023-12-05 05:59:31 28 4
gpt4 key购买 nike

我想制作一个自定义列表序列化程序,它将安全地解析无效的 json 数组。示例:Int 列表 [1, "invalid_int", 2] 应解析为 [1, 2]。我已经制作了一个序列化器并将其添加到 Json 提供程序,但是序列化在第一个元素之后一直失败并且无法继续,所以我得到了 1 个元素 [1] 的列表,我该如何处理无效元素正确所以解码器将继续解析其他元素?


class SafeListSerializerStack<E>(val elementSerializer: KSerializer<E>) : KSerializer<List<E>> {

override val descriptor: SerialDescriptor = ListSerializer(elementSerializer).descriptor

override fun serialize(encoder: Encoder, value: List<E>) {
val size = value.size
val composite = encoder.beginCollection(descriptor, size)
val iterator = value.iterator()
for (index in 0 until size) {
composite.encodeSerializableElement(descriptor, index, elementSerializer, iterator.next())
}
composite.endStructure(descriptor)
}

override fun deserialize(decoder: Decoder): List<E> {
val arrayList = arrayListOf<E>()
try {
val startIndex = arrayList.size
val messageBuilder = StringBuilder()
val compositeDecoder = decoder.beginStructure(descriptor)
while (true) {
val index = compositeDecoder.decodeElementIndex(descriptor) // fails here on number 2
if (index == CompositeDecoder.DECODE_DONE) {
break
}
try {
arrayList.add(index, compositeDecoder.decodeSerializableElement(descriptor, startIndex + index, elementSerializer))
} catch (exception: Exception) {
exception.printStackTrace() // falls here when "invalid_int" is parsed, it's ok
}
}
compositeDecoder.endStructure(descriptor)
if (messageBuilder.isNotBlank()) {
println(messageBuilder.toString())
}
} catch (exception: Exception) {
exception.printStackTrace() // falls here on number 2
}
return arrayList
}
}

解析无效元素后发生错误,并在 compositeDecoder.decodeElementIndex(descriptor) 行抛出异常:

kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 4: Expected end of the array or comma
JSON input: [1, "invalid_int", 2]

我有一种感觉,它应该“吞下”无效元素并继续移动,但它却卡住了,无法继续解析,这对我来说没有意义。

最佳答案

这可以在没有自定义序列化程序的情况下完成。只需将所有内容解析为 String(指定 isLenient = true 以允许不带引号的字符串),然后将所有有效整数转换为 Int:

fun main() {
val input = "[1, \"invalid_int\", 2]"
val result: List<Int> = Json { isLenient = true }
.decodeFromString<List<String>>(input)
.mapNotNull { it.toIntOrNull() }
println(result) // [1, 2]
}

在更通用的情况下(当列表是一个字段和/或其元素不是简单的 Int 时),您将需要一个自定义序列化程序:

class SafeListSerializerStack<E>(private val elementSerializer: KSerializer<E>) : KSerializer<List<E>> {
private val listSerializer = ListSerializer(elementSerializer)
override val descriptor: SerialDescriptor = listSerializer.descriptor

override fun serialize(encoder: Encoder, value: List<E>) {
listSerializer.serialize(encoder, value)
}

override fun deserialize(decoder: Decoder): List<E> = with(decoder as JsonDecoder) {
decodeJsonElement().jsonArray.mapNotNull {
try {
json.decodeFromJsonElement(elementSerializer, it)
} catch (e: SerializationException) {
e.printStackTrace()
null
}
}
}
}

请注意,此解决方案仅适用于 Json 格式的反序列化,并且需要 kotlinx.serialization 1.2.0+

关于json - List 类的自定义 KotlinX 序列化程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68117614/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com