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 序列化添加到您的项目中
Kotlin驾驶员对序列化的支持取决于官方 Kotlin序列化库。
从以下标签页中进行选择,以了解如何使用 Gradle 和 Maven 包管理器将序列化依赖项添加到项目中:
如果您使用 Gradle 要管理依赖项,请将以下内容添加到build.gradle.kts
依赖项列表中:
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.0") implementation("org.mongodb:bson-kotlinx:5.3.0")
如果您使用的是 Maven 要管理依赖项,请将以下内容添加到pom.xml
依赖项列表中:
<dependency> <groupId>org.jetbrains.kotlinx</groupId> <artifactId>kotlinx-serialization-core</artifactId> <version>1.6.0</version> </dependency> <dependency> <groupId>org.mongodb</groupId> <artifactId>bson-kotlinx</artifactId> <version>5.3.0</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", }