我有一个枚举,我想使用kotlinx.serialization从JSON反序列化,同时忽略未知值。
@Serializable
enum class OperatingMode {
Off, On, Auto
}
忽略未知数的意思是,如果JSON对象中有一个或多个模式不在该枚举中,则应将其视为不存在:
{"foo":"bar","mode":"Banana"}
// same as
{"foo":"bar"}
{"modes":["Off","On","Banana"]}
// same as
{"modes":["Off","On"]}
我通过编写自定义序列化程序来实现这一点,但是对于这样一个简单的任务来说,它似乎相当冗长
internal object OperatingModeSafeSerializer : KSerializer<OperatingMode?> {
override val descriptor = PrimitiveSerialDescriptor("OperatingMode", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: OperatingMode?) {
// safe because @Serializable skips null fields
encoder.encodeString(value!!.name)
}
override fun deserialize(decoder: Decoder): OperatingMode? {
val string = decoder.decodeString()
return try {
OperatingMode.valueOf(string)
} catch (_: Exception) {
null
}
}
}
internal object OperatingModeSafeListSerializer: KSerializer<List<OperatingMode>> {
private val delegateSerializer = ListSerializer(OperatingModeSafeSerializer)
override val descriptor = delegateSerializer.descriptor
override fun deserialize(decoder: Decoder): List<OperatingMode> {
return decoder.decodeSerializableValue(delegateSerializer).filterNotNull()
}
override fun serialize(encoder: Encoder, value: List<OperatingMode>) {
encoder.encodeSerializableValue(delegateSerializer, value)
}
}
然后在每个反序列化OperatingMode
的对象中,我可以添加
@Serializable(with = OperatingModeSafeSerializer::class) // or
@Serializable(with = OperatingModeSafeListSerializer::class)
忽略未知数。
问题
1.这是一个巨大的代码量。我希望有更多的枚举,我需要完全相同的行为,我真的不想复制粘贴每个枚举。我不知道如何使这种方法通用,因为这些是对象,不能通用,@Serializable(with = ...)
需要一个编译时常数。
1.理想情况下,我希望将此行为封装在枚举本身中,以便任何对OperatingMode
进行反序列化的操作都将忽略未知数。
2条答案
按热度按时间eyh26e7m1#
目前我认为唯一的方法是使用
coerceInputValues
选项,枚举字段的默认值为null,如本例所示:91zkwejq2#
我找到了一种方法来重构问题中的方法,以避免大多数代码重复。
然后,对于要以这种方式反序列化的每个枚举,只需声明
**注意:*这可能只适用于枚举这样的基本类型。如果您尝试将
SafeSerializer
与复杂类型一起使用,解码器可能会在解析JSON数组或对象这样的结构时抛出异常。捕获该错误将使解码器处于无效状态。一种选择是更改deserialize
,以便首先解码泛型JSON元素,而不捕获错误。 然后 * 在捕获时将其解码为T
,但代价是将串行化器与JSON紧密耦合。如果kotlinx.serialization具有不那么贪婪的解析器,即在抛出之前尝试完全消耗元素,那么这将不是问题。