首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >kotlin:带有泛型的嵌套多态序列化

kotlin:带有泛型的嵌套多态序列化
EN

Stack Overflow用户
提问于 2022-11-02 15:24:50
回答 2查看 88关注 0票数 2

我想序列化Map,其中一个值类型是Pair。如何将这对注册为多态子类?

代码语言:javascript
复制
val module = SerializersModule {
    polymorphic(Any::class) {
        subclass(Int::class, PolymorphicPrimitiveSerializer(Int.serializer()))
        subclass(String::class, PolymorphicPrimitiveSerializer(String.serializer()))
        subclass(Pair::class, PolymorphicSerializer(Pair::class))
    }
}
val format = Json { serializersModule = module }
val mm = mapOf<String, Any>()
        .plus("int-int pair") to (5 to 10))
val jsoned = format.encodeToString(mm)
val mmDecoded = format.decodeFromString(jsoned)
require(mm==mmDecoded)

应该编码到json,比如:

代码语言:javascript
复制
[{"first": "int-int pair", 
"second":{"type": "Pair", "value": 
  {"first": {"type": Int, "value":5}, "second": {"type":Int, "value": 10}}}}]

但会产生以下错误:

线程"main“中由:

序列化程序引起的java.lang.ExceptionInInitializerError异常不能注册为多态序列化的子类,因为它的打开类型不是具体的。要处理多个层次结构,注册为基类。kotlinx.serialization.json.internal.PolymorphismValidator.checkKind(PolymorphismValidator.kt:41) at kotlinx.serialization.json.internal.PolymorphismValidator.polymorphic(PolymorphismValidator.kt:31) at kotlinx.serialization.modules.SerialModuleImpl.dumpTo(SerializersModule.kt:189) at kotlinx.serialization.json.JsonImpl.validateConfiguration(Json.kt:358) at kotlinx.serialization.json.JsonImpl.(Json.kt:352) at kotlinx.serialization.json.JsonKt.Json(Json.kt:189) at kotlinx.serialization.json.JsonKt.Json$default(Json.kt:185) at MainKt.(Main.kt:143)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-11-21 14:47:15

我通过提供自定义多态序列化程序来解决这个问题,类似于我如何序列化map:https://github.com/assafshouval/PolymorphicMapSerializer/blob/master/src/main/kotlin/Main.kt

票数 0
EN

Stack Overflow用户

发布于 2022-11-07 15:47:51

我无法使它与多态子类一起工作,但我认为这个特性并不适合与Any和原语一起使用(参见this question)。自定义序列化程序似乎是一种更合适和更简单的解决方案,与多态序列化不同,它不需要太多的自定义序列化代码:

代码语言:javascript
复制
@ExperimentalSerializationApi
class DynamicLookupSerializer: KSerializer<Any> {
    override val descriptor: SerialDescriptor = ContextualSerializer(Any::class, null, emptyArray()).descriptor

    @OptIn(InternalSerializationApi::class)
    override fun serialize(encoder: Encoder, value: Any) {
        val actualSerializer = encoder.serializersModule.getContextual(value::class) ?: value::class.serializer()
        encoder.encodeSerializableValue(actualSerializer as KSerializer<Any>, value)
    }

    override fun deserialize(decoder: Decoder): Any {
        return try {
            PairSerializer(Int.serializer(), Int.serializer()).deserialize(decoder)
        } catch (e: Throwable) {
            try {
                decoder.decodeInt()
            } catch (e: Throwable) {
                decoder.decodeString()
            }
        }
    }
}

val module = SerializersModule {
    contextual(Any::class, DynamicLookupSerializer())
    contextual(Pair::class) {
        PairSerializer(Int.serializer(), Int.serializer())
    }
}
val format = Json { serializersModule = module }
val mm = mapOf<String, Any>()
    .plus("int-int pair" to (5 to 10))
    .plus("int" to 6)
    .plus("string" to "some string")
    .plus("another-int" to 86248726)
    .plus("another-pair" to (56 to 961))
val jsoned = format.encodeToString(mm)
println(jsoned)
val mmDecoded = format.decodeFromString<Map<String, Any>>(jsoned)
require(mm==mmDecoded)

在这个自定义序列化器中,我们通过value: Any类(value::class)查找序列化时,找到了它的实际序列化程序。因此,PairSerializer(Int.serializer(), Int.serializer())也必须注册,以便在DynamicLookupSerializer.serialize中找到它。反序列化时,我们一个接一个地尝试支持的序列化器(string、int和对int)。

我确实意识到,由于尝试捕获,这不是最好的解决方案,但它确实有效,而且很简单。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74291655

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档