【问题标题】:How to properly use class inheritance in Kotlin in combination with Kotlinx Serialization如何结合 Kotlinx 序列化在 Kotlin 中正确使用类继承
【发布时间】:2021-04-21 18:06:42
【问题描述】:

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

  • 抽象类BaseItem
  • 打开类项目:BaseItem
  • 类背包:物品

它们都应该与 Kotlinx 序列化一起使用。在我添加 Backpack 类之前一切正常。 我使用 Kotlinx 序列化的 1.4.32 版本。

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

// 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 类的以下消息。

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

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

【问题讨论】:

    标签: kotlin kotlinx.serialization


    【解决方案1】:

    这是因为你的构造函数的参数没有定义为类的属性。要将参数定义为属性,您必须将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 用于两个类中使用的所有属性。但无论如何,我对这个设计有点惊讶,因为从非抽象类继承通常不是一个好习惯。在不知道意图的情况下,我想知道 sth.like this 是否对您也不起作用:

    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,因为它是不必要的,因为该类无论如何都是抽象的,因此根本不会被序列化。我还让你的课程data class,因为我的印象是那些基本上是为了保存数据而存在的,而那些通常是用data class 实现的。我留下了许多var,因为我不知道其中的原因,但我这边的一个小提示是,您应该更喜欢val 而不是var,尤其是在data class 中。在这种情况下,var 对我来说就像是代码异味,您可能需要考虑改用 val。 Kotlin 页面本身就是一个很好的文献:https://kotlinlang.org/docs/coding-conventions.html#idiomatic-use-of-language-features

    【讨论】:

      【解决方案2】:

      来自Designing Serializable Hierarchy

      为了使类的层次结构可序列化,必须将父类中的属性标记为抽象,使[父]类也抽象。

      【讨论】:

      • Items 但是不打算使用抽象 - 代码库中已经有它的实例并且应该保持这种方式
      • @xetra11 在这种情况下,BackPack 不能扩展 Item 并且也是可序列化的。您可能需要按照 Big_Foot1989 的建议调整您的类层次结构。
      猜你喜欢
      • 2020-11-20
      • 1970-01-01
      • 1970-01-01
      • 2012-12-26
      • 2021-05-14
      • 2012-10-10
      • 2021-03-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多