如何用kotlinx.serialization将Kotlin密封类序列化为自定义JSON结构
解决kotlinx.serialization密封接口Filter的动态字段序列化问题
问题核心
需要将Filter.NOT(Filter.Field("foo", "bar"))序列化为:
{ "not": { "foo": "bar" } }
核心需求是Field类输出动态键值对结构,而非带类型标识或固定字段的JSON。
问题原因分析
- 自定义序列化器实现错误:原
Field的companion object序列化器中,encodeStructure仅创建了Map但未调用编码方法,导致序列化器错误识别为HashMap类型,输出带类型标识的JSON。 - 密封接口默认类型判别:移除自定义序列化器后,
Field作为密封接口子类会被自动添加类型字段(如"type": "Field"),不符合需求。 - JsonTransformingSerializer空指针:companion object初始化顺序问题,导致调用
serializer()时实例未加载。
修复方案
1. 重新实现Field的自定义序列化器
将序列化器改为独立object(避免初始化顺序问题),正确输出动态键值对:
import kotlinx.serialization.* import kotlinx.serialization.descriptors.mapSerialDescriptor import kotlinx.serialization.encoding.* import kotlinx.serialization.json.Json @Serializable sealed interface Filter { @Serializable @SerialName("not") class NOT(val not: Filter) : Filter // 其他逻辑类(AND/OR)保持原有正确实现 @Serializable @SerialName("and") class AND(val and: List<Filter>) : Filter @Serializable(with = FieldSerializer::class) data class Field(val name: String, val value: String) : Filter } // 独立的Field序列化器,避免companion object初始化问题 object FieldSerializer : KSerializer<Filter.Field> { override val descriptor: SerialDescriptor = mapSerialDescriptor<String, String>() override fun serialize(encoder: Encoder, value: Filter.Field) { // 直接输出单键值对的Map结构 encoder.encodeStringMap(mapOf(value.name to value.value)) } override fun deserialize(decoder: Decoder): Filter.Field { val map = decoder.decodeStringMap() if (map.size != 1) throw SerializationException("Field必须包含且仅包含一个键值对") val (name, value) = map.entries.single() return Filter.Field(name, value) } }
2. 测试序列化
使用默认或自定义Json配置测试:
fun main() { val json = Json { prettyPrint = true } val filter = Filter.NOT(Filter.Field("foo", "bar")) println(json.encodeToString(filter)) }
输出结果
{ "not": { "foo": "bar" } }
关键修复点说明
- 独立序列化器:避免companion object初始化顺序导致的空指针异常,确保序列化器实例在使用前完全加载。
- 正确的序列化逻辑:使用
encodeStringMap直接输出动态键值对,而非错误地在encodeStructure中返回Map。 - 密封接口的@SerialName:
NOT类的@SerialName("not")确保序列化时将"not"作为外层键,包裹内部的Filter实例,符合API要求。
内容的提问来源于stack exchange,提问作者Jan Vladimir Mostert
相关产品推荐
相关产品推荐

