Kotlin 序列化
本页内容
概述
您可以使用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 仓库。
从以下标签中选择,查看如何通过使用以下方法将序列化依赖项添加到您的项目Gradle 或 Maven
如果您使用 Gradle 来管理依赖项,请将以下内容添加到您的 build.gradle.kts
依赖项列表中
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.5.1") implementation("org.mongodb:bson-kotlinx:5.2.0")
如果您使用 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.0</version> </dependency>
注意
bson-kotlin 依赖项
您还可以通过默认编解码器注册表选择性地安装 bson-kotlin
依赖项。此依赖项使用反射和编解码器注册表来支持 Kotlin 数据类,但不支持某些 POJO 注解,如 BsonDiscriminator
、BsonExtraElements
和 BsonConstructor
。有关更多信息,请参阅 bson-kotlin API 文档。
通常,我们建议您安装并使用更快的 bson-kotlinx
库来进行编解码器配置。
注释数据类
要声明一个类为可序列化,请使用 @Serializable
注解来注释您的 Kotlin 数据类。
在将数据类标记为可序列化后,您可以在代码中像使用任何其他数据类一样使用它们。Kotlin Sync 驱动程序和 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 = "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
字段有一个注解,指定了前面代码中定义的自定义序列化器类。
data class PaintOrder( val color: String, val qty: Int, val orderDate: Instant, )
要了解更多关于本节中提到的方法和类,请参阅以下API文档。
KSerializer在Kotlin文档中
Instant 在 Kotlin 文档中
自定义序列化配置
您可以使用来自 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
字段
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") 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 库
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>
要了解更多关于这个库的信息,请参阅GitHub上的kotlinx-datetime仓库。
示例:带有日期和时间的Data Class
添加库依赖后,您可以实现从kotlinx-datetime
库中的序列化器,这些序列化器将您的Data Class字段值映射到BSON中的预期类型。
在此示例中,驱动程序使用以下行为序列化Appointment
数据类的字段
name
:驱动程序将值序列化为字符串。date
:驱动程序使用kotlinx-datetime
序列化器,因为字段具有@Contextual
注解。LocalDate
值序列化为BSON日期。time
:由于没有@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
字段默认使用序列化方式存储为字符串
{ "_id": ..., "name": "Daria Smith", "date": { "$date": "2024-10-15T00:00:00.000Z" }, "time": "11:30", }