Skip to content

序列化 (Serialization)

源:kotlinx.serialization

kotlinx.serialization (KXS) 是 Kotlin 官方推出的无反射、跨平台序列化框架。通过编译器插件在编译阶段生成序列化逻辑,它在性能上显著优于传统的 Gson 和 Jackson,同时原生支持 Kotlin 的空安全、默认参数以及密封类体系。

依赖配置与编译器插件

查看 Maven Central 最新版本

kotlin
plugins {
    // ⭐️ 核心插件:负责在编译期生成 $serializer 类
    kotlin("plugin.serialization") version "2.0.0"
}

dependencies {
    // 基础运行库
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0")
}

基础模型映射与默认值行为

KXS 深度集成 Kotlin 语言特性,特别是在处理缺失字段和 null 值时逻辑严密。

kotlin
@Serializable
data class User(
    val id: Long,
    // ⭐️ 重命名 JSON 键
    @SerialName("user_name") val name: String,
    // ⭐️ 默认值支持:如果 JSON 中缺失此键,将自动使用 false
    val isAdmin: Boolean = false,
    // ⭐️ 自动处理可空类型
    val bio: String? = null
)
kotlin
val json = Json { encodeDefaults = true }
val user = User(1, "Viro")

// 转换为字符串
val string = json.encodeToString(user)
// 结果:{"id":1, "user_name":"Viro", "isAdmin":false, "bio":null}

泛型模型序列化

在开发 API 响应时,经常需要处理泛型包装类(如 Response<T>)。KXS 要求显式传递泛型的序列化器。

kotlin
@Serializable
data class Result<T>(
    val status: Int,
    val data: T
)

// 解析时,必须指定内部 T 的序列化器
val jsonString = """{"status": 200, "data": {"user_name": "Viro"}}"""
val response = Json.decodeFromString<Result<User>>(jsonString)

复杂 JSON 结构处理:JsonElement

当遇到结构不固定或需要动态解析的 JSON 时,可以使用 JsonElement 及其子类。

kotlin
val rawJson = """{"id": 1, "metadata": {"tags": ["kotlin", "android"], "version": 2.0}}"""
val element = Json.parseToJsonElement(rawJson)

// 动态查询
val version = element.jsonObject["metadata"]?.jsonObject?.get("version")?.jsonPrimitive?.double
val tags = element.jsonObject["metadata"]?.jsonObject?.get("tags")?.jsonArray

println("版本: $version") // 2.0

多态与密封类深度集成

KXS 是处理嵌套多态结构的最优雅方案。它会自动管理“类型鉴别器”字段。

kotlin
@Serializable
sealed class NetworkResponse {
    @Serializable
    @SerialName("success") // 定义 type 字段的具体值
    data class Success(val data: String) : NetworkResponse()

    @Serializable
    @SerialName("error")
    data class Error(val code: Int, val message: String) : NetworkResponse()
}
kotlin
// 自动根据 "type" 字段的值分发到对应的子类
val response = Json.decodeFromString<NetworkResponse>(
    """{"type":"error", "code":404, "message":"Not Found"}"""
)

自定义序列化器:KSerializer

用于处理非标准格式(如特殊字符串格式的日期)或第三方库中的类。

kotlin
object DateAsLongSerializer : KSerializer<Date> {
    override val descriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG)

    override fun serialize(encoder: Encoder, value: Date) =
        encoder.encodeLong(value.time)

    override fun deserialize(decoder: Decoder) =
        Date(decoder.decodeLong())
}

@Serializable
data class Event(
    @Serializable(with = DateAsLongSerializer::class)
    val time: Date
)

上下文序列化 (Contextual Serialization)

如果你不想在模型类中硬编码具体的序列化器,可以使用 @Contextual 并在运行时动态注入。

kotlin
@Serializable
data class Data(
    @Contextual val payload: Any // 运行时决定如何序列化
)

val customJson = Json {
    serializersModule = SerializersModule {
        contextual(MyPayload::class, MyPayloadSerializer)
    }
}

内联类序列化 (Value Class) Kotlin 1.5+

Value Class 在序列化时会被“拆箱”,直接表现为其底层数据的类型。这在处理强类型 ID 或包装类时非常高效。

kotlin
@JvmInline
@Serializable
value class UserId(val value: String)

@Serializable
data class Profile(val id: UserId, val name: String)

// 序列化结果:{"id": "user_123", "name": "Viro"}
// 而不是:{"id": {"value": "user_123"}, "name": "Viro"}

全局配置与性能优化

性能避坑准则

  1. 不要局部创建 Json 实例Json { ... } 的构造涉及繁重的序列化器缓存初始化。务必创建一个全局单例并复用。
  2. Streaming 模式:对于大型 JSON(如超过 1MB),应优先使用 decodeFromStream 而非 decodeFromString,以减少字符串分配导致的内存压力。
kotlin
val AppJson = Json {
    ignoreUnknownKeys = true // ⭐️ 忽略未知键,防止后端增加字段导致 Crash
    coerceInputValues = true // ⭐️ 如果后端传 null 但字段是非空带默认值,自动纠正
    prettyPrint = false      // 生产环境关闭美化以减小体积
    isLenient = true         // 允许不规范的 JSON(如 key 无引号)
}

核心工程准则

  1. API 层防御性配置:对接第三方 API 时,务必开启 ignoreUnknownKeys = true
  2. 多态首选密封类:尽可能使用 sealed class 表达多态,相比接口,它能提供更强的编译时完备性检查。
  3. 压缩体积:开启 explicitNulls = false 可以让序列化结果中不包含值为 null 的键,显著减小传输体积。
  4. KMP 环境首选:在任何多平台项目中,KXS 是唯一的、不带平台包袱的序列化选择。