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
相关产品推荐
相关产品推荐

