You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用@Serializable整合MongoDB与Ktor时遭OBJECT_ID序列化错误

解决Ktor整合MongoDB时ObjectId反序列化的类型不匹配问题

问题描述

遇到的错误:

Reading field '_id' failed expected STRING type but found: OBJECT_ID

问题根源是MongoDB中_id字段以ObjectId类型存储,但kotlinx.serialization原生不支持这类BSON专属类型,反序列化时会默认期望String类型,导致类型不匹配。

已尝试的无效方案

  • 使用@BsonId注解直接标记ObjectId类型字段:kotlinx.serialization无法识别ObjectId,仍会触发反序列化错误。
  • 基础自定义序列化器:未正确处理BSON与JSON的序列化逻辑,且未启用ExperimentalSerializationApi实验特性,问题未解决。

可行解决方案

方案一:自定义ObjectId序列化器(保留ObjectId类型)

通过实现kotlinx.serialization的KSerializer接口,将ObjectId与String互相转换,同时结合@BsonId注解实现MongoDB映射:

  1. 编写自定义序列化器(需启用实验特性):
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import org.bson.types.ObjectId

@OptIn(ExperimentalSerializationApi::class)
object ObjectIdSerializer : KSerializer<ObjectId> {
    override val descriptor: SerialDescriptor =
        PrimitiveSerialDescriptor("ObjectId", PrimitiveKind.STRING)

    override fun serialize(encoder: Encoder, value: ObjectId) {
        encoder.encodeString(value.toHexString())
    }

    override fun deserialize(decoder: Decoder): ObjectId {
        return ObjectId(decoder.decodeString())
    }
}
  1. 在数据类中应用序列化器与@BsonId:
@Serializable
data class User(
    @BsonId
    @Serializable(with = ObjectIdSerializer::class)
    val id: ObjectId = ObjectId(), // 提供默认值,插入时自动生成ObjectId
    val googleId: String,
    val email: String,
    val emailVerified: Boolean,
    val givenName: String,
    val familyName: String,
    val profilePicture: String?
)

此方案会在JSON序列化时将ObjectId转为十六进制字符串,MongoDB驱动则通过@BsonId将字段映射为_id,完美兼容BSON与JSON的序列化逻辑。

方案二:将_id字段改为String类型(简化实现)

如果不需要直接操作ObjectId实例,可以将id字段类型改为String,插入时自动生成ObjectId的字符串形式:

@Serializable
data class User(
    @BsonId
    val id: String = ObjectId().toHexString(),
    val googleId: String,
    val email: String,
    val emailVerified: Boolean,
    val givenName: String,
    val familyName: String,
    val profilePicture: String?
)

MongoDB会自动将这个String类型的id存储为ObjectId,反序列化时直接读取为String,避免类型冲突,实现更简洁。

内容的提问来源于stack exchange,提问作者Valentin Valencia Valencia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 16:25:17