Kotlin 序列化
在此页面上
Overview
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 类型
将 Kotlin 序列化添加到您的项目中
Support for serialization in the Kotlin 驾驶员 depends on the official Kotlin serialization library.
从以下标签页中进行选择,以了解如何使用 Gradle 和 Maven 包管理器将序列化依赖项添加到项目中:
如果您使用 Gradle 要管理依赖项,请将以下内容添加到build.gradle.kts
依赖项列表中:
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.5.1") implementation("org.mongodb:bson-kotlinx:5.2.1")
如果您使用的是 Maven 要管理依赖项,请将以下内容添加到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 文档中id
和manufacturer
属性的名称。这样就可以用来代替@BsonId
和@BsonProperty
注解,可序列化类不支持这两种注解。@Contextual
将 BSONid
属性标记为使用内置的ObjectIdSerializer
。要正确序列化 BSON 类型,需要此注释。
data class PaintOrder( // Use instead of @BsonId val id: ObjectId?, val color: String, val qty: Int, 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
字段具有指定前面代码中定义的自定义序列化器类的注解:
data class PaintOrder( val color: String, val qty: Int, val orderDate: Instant, )
有关本节中提到的方法和类的详情,请参阅以下 API 文档:
自定义序列化程序配置
您可以使用 org.bson.codecs.kotlinx
包中的 KotlinSerializerCodec
类为 @Serializable
数据类创建编解码器并自定义存储的内容。
使用 BsonConfiguration
类定义配置,包括是否对默认值进行编码、对 null 进行编码或定义类鉴别器。
要创建自定义编解码器,请在项目中安装 bson-kotlinx
依赖项。从以下标签页中进行选择,以了解如何使用 Gradle 和 Maven 包管理器将依赖项添加到项目中:
注意
bson-kotlin 依赖项
您还可以选择通过默认编解码器注册表安装bson-kotlin
依赖项。 此依赖项使用反射和编解码器注册表来支持 Kotlin 数据类,但不支持某些 POJO 注解,例如BsonDiscriminator
、 BsonExtraElements
和BsonConstructor
。 要了解更多信息,请参阅 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
字段标有注释数据类部分中描述的注释:
sealed interface Person { val name: String } data class Student( val id: ObjectId, override val name: String, val grade: Int, ) : Person data class Teacher( val id: ObjectId, override val name: String, val department: String, ) : Person
然后,您可以像往常一样使用数据类执行操作。 以下示例使用Person
接口对集合进行参数化,然后使用多态类Teacher
和Student
执行操作。 检索文档时,驾驶员会根据鉴别器值自动检测类型,并相应地反序列化它们。
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 库
kotlinx-datetime
是一个Kotlin库,可对日期和时间值的序列化方式提供高级别的控制。 要使用该库,请将kotlinx-datetime
依赖项添加到项目的依赖项列表中。
从以下标签页进行选择,查看如何使用Gradle和Maven包管理器将kotlinx-datetime
依赖项添加到项目中:
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")
<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
值的默认序列化行为。
data class Appointment( val name: String, 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", }