如何使用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
相关产品推荐
相关产品推荐

