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

如何使用Ktor反序列化兼具JsonPrimitive与JsonArray的动态值

处理Ktor中动态类型的value字段反序列化

在Ktor中处理这种动态类型的value字段,核心是利用Kotlinx Serialization的灵活特性,下面提供几种实用方案:

方案一:密封类+自定义序列化器(类型安全推荐)

定义一个密封类封装所有可能的value类型,配合自定义序列化器实现自动适配:

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

// 密封类定义所有可能的value类型
sealed class Value {
    @Serializable
    data class ArrayValue(val items: List<String>) : Value()
    
    @Serializable
    data class StringValue(val content: String) : Value()
    
    @Serializable
    data class BooleanValue(val flag: Boolean) : Value()
}

// 自定义序列化器,处理不同类型的value
object ValueSerializer : KSerializer<Value> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Value", PrimitiveKind.STRING)

    override fun deserialize(decoder: Decoder): Value {
        val jsonElement = decoder as JsonDecoder
        return when (val element = jsonElement.decodeJsonElement()) {
            is JsonArray -> Value.ArrayValue(element.map { it.jsonPrimitive.content })
            is JsonPrimitive -> {
                if (element.isString) {
                    Value.StringValue(element.content)
                } else {
                    Value.BooleanValue(element.boolean)
                }
            }
            else -> throw SerializationException("Unsupported value type")
        }
    }

    override fun serialize(encoder: Encoder, value: Value) {
        val jsonEncoder = encoder as JsonEncoder
        when (value) {
            is Value.ArrayValue -> jsonEncoder.encodeJsonElement(JsonArray(value.items.map { JsonPrimitive(it) }))
            is Value.StringValue -> jsonEncoder.encodeJsonElement(JsonPrimitive(value.content))
            is Value.BooleanValue -> jsonEncoder.encodeJsonElement(JsonPrimitive(value.flag))
        }
    }
}

// 包含动态value的主数据类
@Serializable
data class DynamicData(
    @Serializable(with = ValueSerializer::class) val value: Value
)

使用时直接正常反序列化即可,Ktor会自动调用自定义序列化器适配不同类型:

val json1 = """{"value":["test","rest"]}"""
val data1 = Json.decodeFromString<DynamicData>(json1) // data1.value是ArrayValue

val json2 = """{"value":"test"}"""
val data2 = Json.decodeFromString<DynamicData>(json2) // data2.value是StringValue

val json3 = """{"value":true}"""
val data3 = Json.decodeFromString<DynamicData>(json3) // data3.value是BooleanValue

方案二:直接用JsonElement接收(快速实现)

如果不需要严格的类型封装,可以直接用JsonElement接收value,之后在业务代码中判断类型:

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement

@Serializable
data class DynamicData(
    val value: JsonElement
)

使用时手动解析类型:

val json = """{"value":["test","rest"]}"""
val data = Json.decodeFromString<DynamicData>(json)

when (val value = data.value) {
    is JsonArray -> {
        // 处理数组逻辑,value.map { it.jsonPrimitive.content }
    }
    is JsonPrimitive -> {
        if (value.isString) {
            // 处理字符串逻辑,value.content
        } else {
            // 处理布尔值逻辑,value.boolean
        }
    }
    else -> {
        // 处理其他未知类型
    }
}

方案三:使用JsonContentPolymorphicSerializer

利用Kotlinx Serialization的多态序列化特性,通过JsonContentPolymorphicSerializer自动识别类型:

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

@Serializable
sealed class Value {
    @Serializable
    data class ArrayValue(val items: List<String>) : Value()
    
    @Serializable
    data class StringValue(val content: String) : Value()
    
    @Serializable
    data class BooleanValue(val flag: Boolean) : Value()
}

object ValuePolymorphicSerializer : JsonContentPolymorphicSerializer<Value>(Value::class) {
    override fun selectDeserializer(element: JsonElement): DeserializationStrategy<Value> {
        return when (element) {
            is JsonArray -> ArrayValue.serializer()
            is JsonPrimitive -> {
                if (element.isString) StringValue.serializer() else BooleanValue.serializer()
            }
            else -> throw SerializationException("Unknown value type")
        }
    }
}

@Serializable
data class DynamicData(
    @Serializable(with = ValuePolymorphicSerializer::class) val value: Value
)

这种方式和方案一类似,但利用了官方的多态序列化API,代码更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 15:45:55