I have several classes that I want to deserialize, that include lists of polymorphic types. I can get it to deserialize correctly known types, but deserializing an unknown type throws an exception. What I really want is that the list includes only known types and unknown types are just filtered out. If this could be done in a generic way would be even better.
sealed interface BaseInterface
interface I1 : BaseInterface {
fun f1(): String
}
interface I2: BaseInterface {
fun f2(): String
}
@Serializable
@SerialName("i1")
data class I1Rest(value: String): I1 {
fun f1(): String = value
}
@Serializable
@SerialName("i2")
data class I2Rest(value: String): I2 {
fun f2(): String = value
}
@Serializable
data class SomeClass(list: List<BaseInterface>)
How can I can correctly deserialize SomeClass
with
{ "list": [ {"type": "i1", "value": "v1" }, {"type": "i2", "value": "v2" }, {"type": "i3", "value": "v3" } ] }
If I don't add the i3
type to the json, I can correctly deserialize it using
SerializersModule {
polymorphic(BaseInterface::class){
subclass(I1Rest::class)
subclass(I2Rest::class)
}
}
But as soon as I include an unknown type, it breaks. Note that I don't want to deserialize unknowns to a default type (that would have to extend the base sealed interface). What I want is to ignore/filter the unknowns. (preferably in a generic way) I would also would like to keep the BaseInterface
as an interface and not a class, because I only want to expose interfaces and not concrete classes (this is for a lib)
Ok, this is the best I could come up with:
@Serializable
data class SomeClass(
@Serializable(with = UnknownBaseInterfaceTypeFilteringListSerializer::class)
val list: List<BaseInterface>
)
val json = Json {
ignoreUnknownKeys = true
serializersModule = SerializersModule {
polymorphic(BaseInterface::class) {
subclass(I1Rest::class)
subclass(I2Rest::class)
defaultDeserializer { UnknownTypeSerializer() }
}
}
}
class FilteringListSerializer<E>(private val elementSerializer: KSerializer<E>) : KSerializer<List<E>> {
private val listSerializer = ListSerializer(elementSerializer)
override val descriptor: SerialDescriptor = listSerializer.descriptor
override fun serialize(encoder: Encoder, value: List<E>) {
listSerializer.serialize(encoder, value)
}
override fun deserialize(decoder: Decoder): List<E> = with(decoder as JsonDecoder) {
decodeJsonElement().jsonArray.mapNotNull {
try {
json.decodeFromJsonElement(elementSerializer, it)
} catch (e: UnknownTypeException) {
null
}
}
}
}
class UnknownTypeException(message: String) : SerializationException(message)
open class UnknownTypeSerializer<T> : KSerializer<T> {
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Nothing")
override fun deserialize(decoder: Decoder): T = throw UnknownTypeException("unknown type")
override fun serialize(encoder: Encoder, value: T) = throw UnknownTypeException("unknown type")
}
object UnknownBaseInterfaceTypeFilteringListSerializer : KSerializer<List<BaseInterface>> by FilteringListSerializer(PolymorphicSerializer(BaseInterface::class))
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.