You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

kotlinx-serialization:如何将含多类型对象的JsonArray反序列化为统一类

Kotlin解析混合类型JSON数组为多态Entry类的实现方案

针对你遇到的JSON数组混合字符串与多类型对象的解析需求,我们可以通过Kotlinx.serialization结合自定义序列化器实现类型安全的多态解析,具体步骤如下:

1. 定义密封类与子类

用密封类Entry作为所有条目类型的父类,根据JSON结构定义对应子类:

import kotlinx.serialization.*
import kotlinx.serialization.json.*

// 密封父类,限定所有可能的条目子类
sealed class Entry

// 纯文本条目:对应JSON中的字符串元素
@Serializable
data class EntryText(val content: String) : Entry()

// 列表条目:对应type为"list"的JSON对象
@Serializable
data class EntryList(val items: List<String>) : Entry()

// 子条目组:对应type为"entries"的JSON对象
@Serializable
data class EntrySubEntries(val name: String, val entries: List<Entry>) : Entry()

2. 自定义多态序列化器

由于JSON数组存在无type字段的纯字符串,默认多态规则不适用,需自定义序列化器判断元素类型:

// Entry类的全局多态序列化器
object EntrySerializer : JsonContentPolymorphicSerializer<Entry>(Entry::class) {
    override fun selectDeserializer(element: JsonElement): DeserializationStrategy<Entry> {
        return when {
            // 处理纯字符串元素,映射为EntryText
            element is JsonPrimitive && element.isString -> EntryTextAsStringSerializer
            // 处理JSON对象元素,根据type字段选择子类序列化器
            element is JsonObject -> {
                when (element["type"]?.jsonPrimitive?.content) {
                    "list" -> EntryList.serializer()
                    "entries" -> EntrySubEntries.serializer()
                    else -> throw SerializationException("未知的条目类型: ${element["type"]}")
                }
            }
            else -> throw SerializationException("无法解析的Entry类型")
        }
    }
}

// 专门处理字符串到EntryText的序列化器
object EntryTextAsStringSerializer : KSerializer<EntryText> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("EntryText", PrimitiveKind.STRING)

    override fun serialize(encoder: Encoder, value: EntryText) {
        encoder.encodeString(value.content)
    }

    override fun deserialize(decoder: Decoder): EntryText {
        return EntryText(decoder.decodeString())
    }
}

3. 定义根容器类

创建包含entries字段的根类,并指定使用自定义序列化器:

@Serializable
data class EntryContainer(
    @Serializable(with = EntrySerializer::class)
    val entries: List<Entry>
)

4. 解析示例

使用Json实例解码JSON字符串并验证结果:

fun main() {
    val jsonString = """
        {
            "entries": [
                "Simple Text",
                {
                    "type": "list",
                    "items": [
                        "First Item",
                        "Second Item",
                        "Spectral wings appear on your back, giving you a flying speed of 40 feet."
                    ]
                },
                {
                    "type": "entries",
                    "name": "Sub-Entry",
                    "entries": [
                        "New text but could also be the same as above"
                    ]
                }
            ]
        }
    """.trimIndent()

    // 配置JSON解析器,忽略未知字段以兼容API变更
    val json = Json { ignoreUnknownKeys = true }
    val container = json.decodeFromString(EntryContainer.serializer(), jsonString)

    // 遍历解析结果,演示类型判断
    container.entries.forEach { entry ->
        when (entry) {
            is EntryText -> println("文本条目: ${entry.content}")
            is EntryList -> println("列表条目(共${entry.items.size}项): ${entry.items.joinToString(", ")}")
            is EntrySubEntries -> println("子条目组「${entry.name}」(共${entry.entries.size}个子条目)")
        }
    }
}

关键说明

  • 密封类优势:sealed class Entry确保所有可能的子类都被枚举,避免类型转换错误
  • 类型判断逻辑:先检查是否为字符串,再处理带type字段的对象,覆盖所有JSON元素类型
  • 兼容性:开启ignoreUnknownKeys = true可兼容API新增字段,避免解析失败

依赖配置

确保项目添加Kotlinx.serialization依赖(Gradle示例):

plugins {
    kotlin("plugin.serialization") version "1.9.20"
}

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
}

内容的提问来源于stack exchange,提问作者QT123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 12:22:48