Overview
在应用程序中序列化和反序列化Kotlin对象时,可以使用 kotlinx.serialization库。
该驱动程序提供了一个高效的 Bson 序列化器,您可以将其与标有 @Serializable 注解的类一起使用,以处理Kotlin对象到BSON数据的序列化。
虽然您可以使用Kotlin序列化Json库,但Json序列化器不直接支持ObjectId等BSON值类型。 您必须提供一个可以处理BSON和JSON之间转换的自定义序列化器。
我们建议安装bson-kotlinx库以支持自定义编解码器,这些编解码器具有编码默认值、空值和定义类鉴别器的配置。
注意
要学习;了解如何使用Codec接口而不是kotlinx.serialization库来指定自定义序列化行为,请参阅编解码器指南。
如果您已经熟悉该库或更喜欢使用一致的方法,则可以选择使用Kotlin序列化。
支持的类型
Kotlin Sync驱动程序支持以下类型:
kotlinx.serialization库支持的所有Kotlin类型所有 BSON types
将序列化依赖项添加到项目中
您必须安装官方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 types。
data class PaintOrder( // Use instead of @BsonId val id: ObjectId?, val color: String, val qty: Int, val manufacturer: String? = null // Use instead of @BsonProperty )
注意
POJO 注解限制
您不能在标有@Serializable注解的数据类上使用org.bson.codecs.pojo.annotations包中的注解。
要学习;了解有关可序列化类和可用注解的更多信息,请参阅 kotlinx.serialization库文档中的可序列化类。
自定义序列化器示例
您可以创建自定义序列化器来处理数据在BSON中的表示方式。Kotlin 同步驱动程序使用 kotlinx.serialization 库中的 KSerializer 接口来实现自定义序列化器。您可以将自定义序列化器指定为特定字段的@Serializable 注解的参数。
以下示例介绍如何创建自定义 KSerializer 实例,以将 kotlin.time.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文档:
Kotlin文档中的 KSerializer
自定义序列化程序配置
您可以使用 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 同步驱动程序原生支持多态类的序列化和反序列化。当您使用 @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存储库。
具有日期和时间的数据类示例
添加库依赖项后,您可以实现kotlinx-datetime库中的序列化器,将数据类字段值映射到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字段默认序列化为string存储:
{ "_id": ..., "name": "Daria Smith", "date": { "$date": "2024-10-15T00:00:00.000Z" }, "time": "11:30", }