I have an enum that I'd like to deserialize from JSON using kotlinx.serialization while ignoring unknown values. This is the enum
@Serializable
enum class OperatingMode {
Off, On, Auto
}
What I mean by ignoring unknowns is if I have a mode or modes in a JSON object which are not in that enum, they should be treated as absent:
{"foo":"bar","mode":"Banana"}
// same as
{"foo":"bar"}
{"modes":["Off","On","Banana"]}
// same as
{"modes":["Off","On"]}
I got this to work by writing custom serializers, but it seems quite verbose for such a simple task
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)
}
}
Then in each object which is deserializing OperatingMode
I can add
@Serializable(with = OperatingModeSafeSerializer::class) // or
@Serializable(with = OperatingModeSafeListSerializer::class)
to ignore unknowns.
Problems
- This is a huge amount of code. I expect to have more enums for which I will need the exact same behavior and I really don't want to copy-paste this for each one. I don't know how to make this approach generic because these are objects which can't be generic and
@Serializable(with = ...)
needs a compile-time constant. - Ideally I'd want this behavior to be encapsulated in the enum itself, so that anything deserializing an
OperatingMode
will ignore unknowns.