如何结合 Kotlinx 序列化在 Kotlin 中正确使用 class 继承
How to properly use class inheritance in Kotlin in combination with Kotlinx Serialization
我有一个包含以下内容的简单层次结构:
- 抽象 class BaseItem
- 打开 class 物品:基础物品
- class 背包:物品
它们都应该与 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 的属性。要将参数定义为属性,您必须向参数添加 val
或 var
。这将解决您当前的错误消息:
@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
我有一个包含以下内容的简单层次结构:
- 抽象 class BaseItem
- 打开 class 物品:基础物品
- class 背包:物品
它们都应该与 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 的属性。要将参数定义为属性,您必须向参数添加 val
或 var
。这将解决您当前的错误消息:
@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