Kotlin多JSON格式反序列化为单个类:优化实现咨询
处理Kotlinx.serialization中ControlData的多格式反序列化问题
问题背景
现有Kotlin类ControlData用于表示控制数据:
@Serializable(with = ControlSerializer::class) class ControlData( val start: Double, val end: Double, val offset: Double?, val ramp: Double?, )
需要从两种JSON格式反序列化:
- 格式一(对象形式):
{ "control": { "start": 0.5, "end": 1.0, "offset": 3.0, "ramp": 2.0 } }
- 格式二(单个数值):
{ "control": 2.0 }
格式二中的数值需映射为start和end,offset和ramp设为null。
当前通过JsonContentPolymorphicSerializer实现,但需手动重写序列化逻辑,提出两个问题:
- 设置自定义序列化器后,能否访问类的默认序列化器以避免手动重写?
- 是否有更优方式实现该反序列化需求?
问题1解答:可以复用默认序列化器
完全可以通过ControlData.serializer()获取编译器自动生成的默认序列化器,无需手动实现对象格式的反序列化逻辑。只需将自定义的ObjectSerializer代理给默认序列化器即可:
object ObjectSerializer : KSerializer<ControlData> by ControlData.serializer()
这样直接复用了默认序列化器的所有逻辑,省去手动提取JSON元素的繁琐代码。
问题2解答:更简洁的自定义序列化器实现
不需要使用JsonContentPolymorphicSerializer,直接编写一个自定义序列化器,在deserialize方法中区分JSON元素类型处理即可,同时复用默认序列化器处理对象格式:
@Serializable(with = ControlDataSerializer::class) class ControlData( val start: Double, val end: Double, val offset: Double?, val ramp: Double?, ) object ControlDataSerializer : KSerializer<ControlData> { private val defaultSerializer = ControlData.serializer() override val descriptor: SerialDescriptor = defaultSerializer.descriptor // 序列化逻辑可直接复用默认实现,若无需序列化可保留空实现(但接口要求实现) override fun serialize(encoder: Encoder, value: ControlData) { defaultSerializer.serialize(encoder, value) } override fun deserialize(decoder: Decoder): ControlData { val jsonElement = decoder.decodeJsonElement() return when (jsonElement) { // 处理单个数值格式 is JsonPrimitive -> { val value = jsonElement.double ControlData(value, value, null, null) } // 处理对象格式,复用默认序列化器 is JsonObject -> defaultSerializer.deserialize(Json.decodeFromJsonElement(jsonElement)) else -> throw SerializationException("不支持的ControlData JSON格式") } } }
补充:处理外层control字段
如果根JSON始终包含control键,建议定义一个包装类简化反序列化:
@Serializable data class ControlWrapper(val control: ControlData)
使用时直接调用:
val json = "{\"control\":2.0}" val wrapper = Json.decodeFromString<ControlWrapper>(json) val controlData = wrapper.control
内容的提问来源于stack exchange,提问作者fill1890
相关产品推荐
相关产品推荐

