序列化 (Serialization)
kotlinx.serialization (KXS) 是 Kotlin 官方推出的无反射、跨平台序列化框架。通过编译器插件在编译阶段生成序列化逻辑,它在性能上显著优于传统的 Gson 和 Jackson,同时原生支持 Kotlin 的空安全、默认参数以及密封类体系。
依赖配置与编译器插件
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"}全局配置与性能优化
性能避坑准则
- 不要局部创建 Json 实例:
Json { ... }的构造涉及繁重的序列化器缓存初始化。务必创建一个全局单例并复用。 - Streaming 模式:对于大型 JSON(如超过 1MB),应优先使用
decodeFromStream而非decodeFromString,以减少字符串分配导致的内存压力。
kotlin
val AppJson = Json {
ignoreUnknownKeys = true // ⭐️ 忽略未知键,防止后端增加字段导致 Crash
coerceInputValues = true // ⭐️ 如果后端传 null 但字段是非空带默认值,自动纠正
prettyPrint = false // 生产环境关闭美化以减小体积
isLenient = true // 允许不规范的 JSON(如 key 无引号)
}核心工程准则
- API 层防御性配置:对接第三方 API 时,务必开启
ignoreUnknownKeys = true。 - 多态首选密封类:尽可能使用
sealed class表达多态,相比接口,它能提供更强的编译时完备性检查。 - 压缩体积:开启
explicitNulls = false可以让序列化结果中不包含值为 null 的键,显著减小传输体积。 - KMP 环境首选:在任何多平台项目中,KXS 是唯一的、不带平台包袱的序列化选择。