如何结合 Kotlinx 序列化在 Kotlin 中正确使用 class 继承

How to properly use class inheritance in Kotlin in combination with Kotlinx Serialization

我有一个包含以下内容的简单层次结构:

它们都应该与 Kotlinx 序列化一起工作。在我添加 Backpack class 之前一切顺利。 我使用 Kotlinx 序列化版本 1.4.32

这是我的 class 层次结构的详细信息

// Items.kt

@Serializable
sealed class BaseItem {
    abstract val id: String
    abstract val type: ItemType
    abstract var brand: String
    abstract var model: String
    abstract var imageLink: String
    abstract var traits: MutableList<Trait>
    abstract var implicitTraits: MutableList<Trait>
    abstract var details: MutableMap<String, String>
}

@Serializable
open class Item(
    override val id: String = UUID.randomUUID().toString(),
    override val type: ItemType = ItemType.UNDEFINED,
    override var brand: String,
    override var model: String,
    override var imageLink: String,
    override var traits: MutableList<Trait>,
    override var implicitTraits: MutableList<Trait>,
    override var details: MutableMap<String, String>,
) : BaseItem()

@Serializable // is marked as incorrect 
class Backpack(
    brand: String,
    model: String,
    imageLink: String,
    traits: MutableList<Trait>,
    implicitTraits: MutableList<Trait>,
    details: MutableMap<String, String>,
    var volume: Int
) : Item(
    type = ItemType.BACKPACK,
    brand = brand,
    model = model,
    imageLink = imageLink,
    traits = traits,
    implicitTraits = implicitTraits,
    details = details
)

IDE 显示 @Serialization 注释的以下消息 Backpack class。

This class is not serializable automatically because it has primary constructor parameters that are not properties

我无法找出正确的工作方式

来自Designing Serializable Hierarchy

To make hierarchy of classes serializable, the properties in the parent class have to be marked abstract, making the [parent] class abstract, too.

这是因为您的构造函数的参数未定义为 class 的属性。要将参数定义为属性,您必须向参数添加 valvar。这将解决您当前的错误消息:

@Serializable
class Backpack(
    override var brand: String,
    override var model: String,
    override var imageLink: String,
    override var traits: MutableList<Trait>,
    override var implicitTraits: MutableList<Trait>,
    override var details: MutableMap<String, String>,
    var volume: Int
) : Item(
    type = ItemType.BACKPACK,
    brand = brand,
    model = model,
    imageLink = imageLink,
    traits = traits,
    implicitTraits = implicitTraits,
    details = details
)

但这仍然无法编译,因为您最终会得到 Serializable class has duplicate serial name of property 'brand', either in the class itself or its supertypes 两个 classes 中使用的所有属性。但无论如何,我对设计感到有点惊讶,因为从非抽象 class 继承通常不是一个好习惯。在不知道意图的情况下,我想知道 sth.like 这是否对你也不起作用:

sealed class BaseItem {
    abstract val id: String
    abstract val type: ItemType
    abstract var brand: String
    abstract var model: String
    abstract var imageLink: String
    abstract var traits: MutableList<Trait>
    abstract var implicitTraits: MutableList<Trait>
    abstract var details: MutableMap<String, String>
}

@Serializable
data class Item(
    override val id: String = UUID.randomUUID().toString(),
    override val type: ItemType = ItemType.UNDEFINED,
    override var brand: String,
    override var model: String,
    override var imageLink: String,
    override var traits: MutableList<Trait>,
    override var implicitTraits: MutableList<Trait>,
    override var details: MutableMap<String, String>,
) : BaseItem()

@Serializable
data class Backpack(
    override val id: String = UUID.randomUUID().toString(),
    override val type: ItemType = ItemType.BACKPACK,
    override var brand: String,
    override var model: String,
    override var imageLink: String,
    override var traits: MutableList<Trait>,
    override var implicitTraits: MutableList<Trait>,
    override var details: MutableMap<String, String>,
    override var var volume: Int
) : BaseItem()

我顺便说一句。从 BaseItem 中删除了 @Serializable,因为它是不必要的,因为 class 无论如何都是抽象的,因此根本不会被序列化。我还制作了您的 classes data class,因为我的印象是这些基本上是用来保存数据的,而且通常是用 data class 实现的。我留下了很多我看到的 var,因为我不知道这些的原因,但我这边的一个小提示是你应该更喜欢 val 而不是 var 尤其是 data class.在这种情况下,var 对我来说感觉像是一种代码味道,您可能需要考虑改用 val。 Kotlin 页面本身就是此类事情的一个很好的文献:https://kotlinlang.org/docs/coding-conventions.html#idiomatic-use-of-language-features