文档菜单
文档首页
/ / /
Kotlin 同步驱动程序
/

Kotlin 序列化

本页内容

  • 概述
  • 支持类型
  • 将序列化依赖项添加到您的项目中
  • 注释数据类
  • 自定义序列化器示例
  • 自定义序列化器配置
  • 自定义编解码器示例
  • 多态序列化
  • 多态数据类示例
  • 序列化日期和时间
  • kotlinx-datetime 库
  • 带有日期和时间的示例数据类

您可以使用kotlinx.serialization 库在您的应用程序中序列化和反序列化 Kotlin 对象。

驱动程序提供了一个高效的 Bson 序列化器,您可以使用带有 @Serializable 注解的类来处理将 Kotlin 对象序列化为 BSON 数据。

尽管您可以使用 Kotlin 序列化 Json 库,但 Json 序列化器 不直接 支持 BSON 值类型,如 ObjectId。您必须提供一个自定义序列化器,以处理 BSON 和 JSON 之间的转换。

我们建议安装 bson-kotlinx 库以支持具有配置以编码默认值、nulls 和定义类区分符的自定义编解码器。

注意

要了解如何使用 Codec 接口而不是 kotlinx.serialization 库来指定自定义序列化行为,请参阅编解码器 指南。

如果您已经熟悉该库或更喜欢使用惯用方法,则可能会选择使用 Kotlin 序列化。

Kotlin Sync 驱动支持以下类型

  • 所有由 kotlinx.serialization 库支持的 Kotlin 类型

  • 所有BSON 类型

您必须安装官方的 Kotlin 序列化库 kotlinx.serialization,以在您的应用程序中序列化和反序列化数据。有关此库的更多信息,请参阅 kotlinx.serialization GitHub 仓库。

从以下标签中选择,查看如何通过使用以下方法将序列化依赖项添加到您的项目GradleMaven

如果您使用 Gradle 来管理依赖项,请将以下内容添加到您的 build.gradle.kts 依赖项列表中

build.gradle.kts
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.5.1")
implementation("org.mongodb:bson-kotlinx:5.2.0")

如果您使用 Maven 来管理依赖项,请将以下内容添加到您的 pom.xml 依赖项列表中

pom.xml
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-serialization-core</artifactId>
<version>1.5.1</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>bson-kotlinx</artifactId>
<version>5.2.0</version>
</dependency>

注意

bson-kotlin 依赖项

您还可以通过默认编解码器注册表选择性地安装 bson-kotlin 依赖项。此依赖项使用反射和编解码器注册表来支持 Kotlin 数据类,但不支持某些 POJO 注解,如 BsonDiscriminatorBsonExtraElementsBsonConstructor。有关更多信息,请参阅 bson-kotlin API 文档。

通常,我们建议您安装并使用更快的 bson-kotlinx 库来进行编解码器配置。

要声明一个类为可序列化,请使用 @Serializable 注解来注释您的 Kotlin 数据类。

在将数据类标记为可序列化后,您可以在代码中像使用任何其他数据类一样使用它们。Kotlin Sync 驱动程序和 Kotlin 序列化框架处理 BSON 序列化和反序列化。

此示例展示了具有以下注释的样本数据类

  • @Serializable:标记该类为可序列化。

  • @SerialName:指定 BSON 文档中 idmanufacturer 属性的名称。此注解可以替代不适用于可序列化类的 @BsonId@BsonProperty 注解。

  • @Contextual:标记 BSON id 属性以使用内置的 ObjectIdSerializer。此注解对于驱动程序正确序列化 BSON 类型是必需的。

@Serializable
data class PaintOrder(
@SerialName("_id") // Use instead of @BsonId
@Contextual val id: ObjectId?,
val color: String,
val qty: Int,
@SerialName("brand")
val manufacturer: String = "Grumbacher" // Use instead of @BsonProperty
)

注意

POJO 注解限制

您不能在标记有 @Serializable 注解的数据类上使用 org.bson.codecs.pojo.annotations 包中的注解。

有关可序列化类和可用注解的更多信息,请参阅 kotlinx.serialization 库文档中的 可序列化类

您可以通过创建自定义序列化器来处理数据在BSON中的表示方式。Kotlin Sync驱动使用来自kotlinx.serialization库的KSerializer接口来实现自定义序列化器。您可以将自定义序列化器作为参数指定给特定字段的@Serializable注解。

以下示例展示了如何创建一个自定义的KSerializer实例,将kotlinx.datetime.Instant转换为BsonDateTime

object InstantAsBsonDateTime : KSerializer<Instant> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("InstantAsBsonDateTime", PrimitiveKind.LONG)
override fun serialize(encoder: Encoder, value: Instant) {
when (encoder) {
is BsonEncoder -> encoder.encodeBsonValue(BsonDateTime(value.toEpochMilli()))
else -> throw SerializationException("Instant is not supported by ${encoder::class}")
}
}
override fun deserialize(decoder: Decoder): Instant {
return when (decoder) {
is BsonDecoder -> Instant.ofEpochMilli(decoder.decodeBsonValue().asDateTime().value)
else -> throw SerializationException("Instant is not supported by ${decoder::class}")
}
}
}

以下代码展示了包含PaintOrder数据类的代码,其中orderDate字段有一个注解,指定了前面代码中定义的自定义序列化器类。

@Serializable
data class PaintOrder(
val color: String,
val qty: Int,
@Serializable(with = InstantAsBsonDateTime::class)
val orderDate: Instant,
)

要了解更多关于本节中提到的方法和类,请参阅以下API文档。

您可以使用来自 org.bson.codecs.kotlinx 包的 KotlinSerializerCodec 类来创建针对您的 @Serializable 数据类的编解码器,并自定义驱动在 MongoDB 中存储的内容。

使用 BsonConfiguration 类来定义配置,这可以包括是否编码默认值、编码空值或定义类区分符。

要创建自定义编解码器,您的项目必须包含 bson-kotlinx 依赖项。请参阅本指南中的 将序列化依赖项添加到您的项目 部分,以获取安装说明。

您可以通过使用 KotlinSerializerCodec.create() 方法来定义您的编解码器,然后您可以将其添加到注册表中。

以下示例展示了如何使用KotlinSerializerCodec.create()方法创建编解码器,然后配置它不编码默认值

val myCustomCodec = KotlinSerializerCodec.create<PaintOrder>(
bsonConfiguration = BsonConfiguration(encodeDefaults = false)
)
val registry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(myCustomCodec), collection.codecRegistry
)

要了解更多关于本节中提到的方法和类,请参阅以下API文档。

Kotlin Sync 驱动程序原生支持多态类的序列化和反序列化。当你使用@Serializable注解标记一个密封接口及其继承该接口的数据类时,驱动程序使用KSerializer实现来处理你的类型与BSON之间的转换。

当你将多态数据类的实例插入MongoDB时,驱动程序会添加字段_t,即判别器字段。该字段的值是数据类的名称。

以下示例创建了一个接口和两个继承该接口的数据类。在数据类中,使用标注数据类部分中描述的注解标记了id字段

@Serializable
sealed interface Person {
val name: String
}
@Serializable
data class Student(
@Contextual
@SerialName("_id")
val id: ObjectId,
override val name: String,
val grade: Int,
) : Person
@Serializable
data class Teacher(
@Contextual
@SerialName("_id")
val id: ObjectId,
override val name: String,
val department: String,
) : Person

然后,您可以像平常一样使用数据类进行操作。以下示例使用Person接口对集合进行参数化,然后对多态类TeacherStudent进行操作。当您检索文档时,驱动程序会根据判别器值自动检测类型并相应地进行反序列化。

val collection = database.getCollection<Person>("school")
val teacherDoc = Teacher(ObjectId(), "Vivian Lee", "History")
val studentDoc = Student(ObjectId(), "Kate Parker", 10)
collection.insertOne(teacherDoc)
collection.insertOne(studentDoc)
println("Retrieving by using data classes")
val resultTeacher = collection.withDocumentClass<Teacher>()
.find(Filters.exists("department"))
.firstOrNull()
println(resultTeacher)
val resultStudent = collection.withDocumentClass<Student>()
.find(Filters.exists("grade"))
.firstOrNull()
println(resultStudent)
println("\nRetrieving by using Person interface")
val resultsPerson = collection.withDocumentClass<Person>().find()
resultsPerson.forEach { result ->
println(result)
}
println("\nRetrieving as Document type")
val resultsDocument = collection.withDocumentClass<Document>().find()
resultsDocument.forEach { result ->
println(result)
}
Retrieving by using data classes
Teacher(id=..., name=Vivian Lee, department=History)
Student(id=..., name=Kate Parker, grade=10)
Retrieving by using Person interface
Teacher(id=..., name=Vivian Lee, department=History)
Student(id=..., name=Kate Parker, grade=10)
Retrieving as Document type
Document{{_id=..., _t=Teacher, name=Vivian Lee, department=History}}
Document{{_id=..., _t=Student, name=Kate Parker, grade=10}}

在本节中,您可以了解如何使用Kotlin序列化处理日期和时间类型。

kotlinx-datetime是一个Kotlin库,它提供了对您的日期和时间值序列化的高级控制。要使用该库,请将kotlinx-datetime依赖项添加到您的项目依赖项列表中。

选择以下选项卡,了解如何使用GradleMaven包管理器将kotlinx-datetime依赖项添加到您的项目中。

build.gradle.kts
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")
pom.xml
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-datetime-jvm</artifactId>
<version>0.6.1</version>
</dependency>

要了解更多关于这个库的信息,请参阅GitHub上的kotlinx-datetime仓库

添加库依赖后,您可以实现从kotlinx-datetime库中的序列化器,这些序列化器将您的Data Class字段值映射到BSON中的预期类型。

在此示例中,驱动程序使用以下行为序列化Appointment数据类的字段

  • name:驱动程序将值序列化为字符串。

  • date:驱动程序使用kotlinx-datetime序列化器,因为字段具有@Contextual注解。LocalDate值序列化为BSON日期。

  • time:由于没有@Contextual注解,驱动程序将值序列化为字符串。这是LocalTime值的默认序列化行为。

@Serializable
data class Appointment(
val name: String,
@Contextual val date: LocalDate,
val time: LocalTime,
)

以下示例将Appointment数据类的实例插入到appointments集合中

val collection = database.getCollection<Appointment>("appointments")
val apptDoc = Appointment(
"Daria Smith",
LocalDate(2024, 10, 15),
LocalTime(hour = 11, minute = 30)
)
collection.insertOne(apptDoc)

在MongoDB中,LocalDate值以BSON日期的形式存储,而time字段默认使用序列化方式存储为字符串

{
"_id": ...,
"name": "Daria Smith",
"date": {
"$date": "2024-10-15T00:00:00.000Z"
},
"time": "11:30",
}

返回

专用数据格式