Docs 菜单
Docs 主页
/ / /
Kotlin 协程
/ /

Kotlin 序列化

在此页面上

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

Kotlin 驱动程序支持用于序列化和反序列化 Kotlin 对象的 kotlinx.serialization 库。

驱动程序提供了高效的 Bson 序列化器,您可以将其与标记为 @Serializable 的类一起使用,将 Kotlin 对象序列化为 BSON 数据。

您还可以安装 bson-kotlinx 库来支持 自定义编解码器,并配置编码默认值、编码空值和定义类鉴别器。

注意

要学习;了解如何使用Codec接口而不是Kotlin序列化库来指定将Kotlin对象自定义编码和解码为BSON数据,请参阅编解码器指南。

如果您已熟悉此框架或更想使用惯用的 Kotlin 方法,则可选择 Kotlin 序列化。

虽然您可以将 Kotlin 驱动程序与 Kotlin 序列化 Json 库一起使用,但 Json 序列化器并直接支持 BSON 值类型(如 ObjectId)。您必须提供能处理 BSON 和 JSON 之间转换的自定义序列化器。

Kotlin 驱动程序支持:

  • Kotlin 序列化库支持的所有 Kotlin 类型

  • 所有可用的 BSON 类型

Support for serialization in the Kotlin 驾驶员 depends on the official Kotlin serialization library.

从以下标签页中进行选择,以了解如何使用 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.1")

如果您使用的是 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.1</version>
</dependency>

要将类声明为可序列化,请使用 Kotlin 序列化框架中的 @Serializable 注释来注释 Kotlin 数据类。

在将数据类标记为可序列化后,您可以在代码中正常使用这些类。Kotlin 驱动程序和 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 = "Acme" // Use instead of @BsonProperty
)

注意

您不能在 @Serializable 数据类上使用 org.bson.codecs.pojo.annotations 包中的注释

有关可序列化类和可用注解类的更多信息,请参阅 Kotlin 序列化官方文档。

您可以创建自定义序列化器以处理如何在 BSON 中表示数据。Kotlin 驱动程序使用 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.toEpochMilliseconds()))
else -> throw SerializationException("Instant is not supported by ${encoder::class}")
}
}
override fun deserialize(decoder: Decoder): Instant {
return when (decoder) {
is BsonDecoder -> Instant.fromEpochMilliseconds(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 数据类创建编解码器并自定义存储的内容。

使用 BsonConfiguration 类定义配置,包括是否对默认值进行编码、对 null 进行编码或定义类鉴别器。

要创建自定义编解码器,请在项目中安装 bson-kotlinx 依赖项。从以下标签页中进行选择,以了解如何使用 GradleMaven 包管理器将依赖项添加到项目中:

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

build.gradle.kts
implementation("org.mongodb:bson-kotlinx:5.2.1")

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

pom.xml
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>bson-kotlinx</artifactId>
<version>5.2.1</version>
</dependency>

注意

bson-kotlin 依赖项

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

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

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

以下示例展示了如何使用 KotlinSerializerCodec.create() 方法创建编解码器,并将其配置为不对默认值编码:

import org.bson.codecs.configuration.CodecRegistries
import org.bson.codecs.kotlinx.BsonConfiguration
import org.bson.codecs.kotlinx.KotlinSerializerCodec
val myCustomCodec = KotlinSerializerCodec.create<PaintOrder>(
bsonConfiguration = BsonConfiguration(encodeDefaults = false)
)
val registry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(myCustomCodec), collection.codecRegistry
)

有关本节中提到的方法和类的详情,请参阅以下 API 文档:

Kotlin驾驶员原生支持多态类的序列化和反序列化。 当您使用@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")
collection.withDocumentClass<Teacher>()
.find(Filters.exists("department"))
.first().also { println(it) }
collection.withDocumentClass<Student>()
.find(Filters.exists("grade"))
.first().also { println(it) }
println("\nRetrieving by using Person interface")
val resultsFlow = collection.withDocumentClass<Person>().find()
resultsFlow.collect { println(it) }
println("\nRetrieving as Document type")
val resultsDocFlow = collection.withDocumentClass<Document>().find()
resultsDocFlow.collect { println(it) }
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>

要学习;了解有关此库的更多信息,请参阅 kotlinx-datetime存储库 在Github 上。

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

在此示例中,驾驶员通过以下行为序列化Appointment数据类的字段:

  • name:驾驶员将该值序列化为string 。

  • date:驾驶员使用kotlinx-datetime序列化器,因为该字段具有@Contextual注解。 LocalDate值被序列化为BSON日期。

  • time:驾驶员将该值序列化为string ,因为它没有 @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字段默认序列化为string存储:

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

后退

文档 (Document)