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类型
将序列化依赖项添加到项目中
您必须安装官方Kotlin序列化库 kotlinx.serialization 才能对应用程序中的数据进行序列化和反序列化。要学习;了解有关此库的更多信息,请参阅kotlinx.serialization Github存储库。
提示
物料清单
我们建议将Java虚拟机(JVM)驱动程序物料清单 (BOM) 添加到您的应用程序中,以管理驱动程序工件的版本。这删除了为 BOM 涵盖的任何单个包指定版本的需要,从而简化了依赖项管理。要学习;了解更多信息,请参阅入门指南中的“添加驱动程序物料清单”步骤。
从以下标签页中进行选择,查看如何使用Gradle或Maven将序列化依赖项添加到项目中:
If you are using Gradle to manage your dependencies, add the following to your build.gradle.kts dependencies list:
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.0") implementation("org.mongodb:bson-kotlinx")
If you are using Maven to manage your dependencies, add the following to your pom.xml dependencies list:
<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> </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包中的注解。
To learn more about serializable classes and available annotations, see Serializable classes in the kotlinx.serialization library documentation.
查询带注解的类
You can query annotated data classes by using the Filters class from the mongodb-driver-kotlin-extensions package. This class allows you to create query filters on field names annotated with the @SerialName annotation.
提示
要使用扩展库中的 Filters 类,必须将 mongodb-driver-kotlin-extensions 依赖项添加到项目中。有关更多信息,请参阅《将构建器与数据类结合使用》指南的“在项目中添加Kotlin扩展”部分。
以下示例查询 orders集合中 brand字段值为 "Sherwin-Williams" 的文档:
val queryFilter = eq(PaintOrder::manufacturer, "Sherwin-Williams") val results = collection.find(queryFilter).toList()
前面的代码创建了一个查询筛选条件,该筛选器引用 PaintOrder::manufacturer属性但查询 brand BSON字段。驱动程序会自动将数据类属性名称转换为 @SerialName 注解中指定的字段名称。
自定义序列化器示例
您可以创建自定义序列化器来处理数据在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
Instant in the Kotlin documentation
自定义序列化程序配置
您可以使用 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 )
实施蛇形命名策略
使用 bson-kotlinx包v5.4 时或更高版本中,您可以指示驱动程序将以驼峰命名法写入的数据类字段名称序列化为MongoDB中的蛇形命名法。以下示例展示了如何创建并注册自定义编解码器,通过在编解码器中设置 bsonNamingStrategy 参数,将数据类字段名称转换为蛇形命名法:
val myCustomCodec = KotlinSerializerCodec.create<PaintOrder>( bsonConfiguration = BsonConfiguration(bsonNamingStrategy = BsonNamingStrategy.SNAKE_CASE) ) 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", }