【问题标题】:KotlinX serialization - Polymorphic content using sealedKotlinX 序列化 - 使用密封的多态内容
【发布时间】:2019-09-05 08:57:00
【问题描述】:

假设我有以下 json 对象:

{
    "type": "video",
    "...": "..."
}
{
    "type": "image",
    "...": "..."
}

它们都代表媒体对象。 Kotlin 密封模型看起来像:

sealed class Media {
    ...
}

@Serializable
@SerialName("video")
data class Video(...) : Media()

@Serializable
@SerialName("image")
data class Image(...) : Media()

根据 KoltinX 文档,我使用包装器进行多态序列化:

@Serializable
private data class MediaWrapper(@Polymorphic val media: Media) {
    companion object {
        val jsonSerializer = Json(
            context = SerializersModule {
                polymorphic<Media> {
                    Video::class with Video.serializer()
                    Image::class with Image.serializer()
                }
            }
        )

        fun fromJson(json: String) = jsonSerializer.parse(serializer(), json)
    }
}

目标是使用我的包装器反序列化Media json,但问题是我需要将我的Media json 更改为MediaWrapper json。 我找到的最方便的解决方案是在我的Media json 的每一侧添加{\"media\":\"\"}

sealed class Media {
    companion object {
        fun fromJson(mediaJson: String): Media {
            val mediaWrapperJson = "{\"media\":$mediaJson}"
            val mediaWrapper = MediaWrapper.fromJson(mediaWrapperJson)
            return mediaWrapper.media
        }
    }
}

这是一个技巧,如果有更方便的反序列化多态的方法,请告诉我!

【问题讨论】:

  • 我应该如何将其应用于包含该字段的数据类?使用@SerializableName 然后编写自定义反序列化器?请延长

标签: json kotlin serialization polymorphism sealed-class


【解决方案1】:

虽然 kotlinx 序列化文档在其许多多态示例中使用包装器,但它并没有说这种模式是强制性的。

来自文档:

专业提示:要在没有包装器的情况下使用 Message,您可以传递 PolymorphicSerializer(Message::class) 来解析/字符串化。

在你的情况下,你可以这样做:

sealed class Media {
    companion object {
        val jsonSerializer = Json(
            context = SerializersModule {
                polymorphic<Media> {
                    Video::class with Video.serializer()
                    Image::class with Image.serializer()
                }
            }
        )

        fun fromJson(mediaJson: String): Media {
           return jsonSerializer.parse(PolymorphicSerializer(Media::class), mediaJson) as Media
        }
    }
}

【讨论】:

  • 工作非常感谢!只是一个细节:Type inference failed. Expected type mismatch. Requiered: Media. Found: Any 我必须在parse 之后加上as Media 演员
  • 对我来说,直到我意识到 kotlinx 需要 JSON 中的 "type" 属性来区分类之前,这才起作用。所以,如果你用@SerialName("video")装饰Video,输入的JSON字符串应该看起来像{ "type": "video", ... }
  • 我应该如何将其应用于包含该字段的数据类?使用@SerializableName 然后编写自定义反序列化器?请延长
猜你喜欢
  • 2022-07-22
  • 2020-11-20
  • 1970-01-01
  • 1970-01-01
  • 2020-02-15
  • 2020-09-15
  • 1970-01-01
  • 2020-03-09
  • 2019-12-31
相关资源
最近更新 更多