Kotlin JSON 序列化实战:使用 Kotlinx.serialization – wiki基地


Kotlin JSON 序列化实战:深入探索 Kotlinx.serialization

在现代软件开发中,JSON (JavaScript Object Notation) 已成为数据交换的事实标准。无论是与后端 API 通信、存储配置信息,还是在不同服务间传递数据,我们都离不开将内存中的对象(Object)转换为 JSON 字符串(序列化)以及将 JSON 字符串转换回对象(反序列化)的过程。对于 Kotlin 开发者而言,虽然可以使用像 Jackson 或 Gson 这样的 Java 生态库,但 Kotlin 官方提供了更为现代、类型安全且与 Kotlin 语言特性深度集成的解决方案——kotlinx.serialization

kotlinx.serialization 是一个由 JetBrains 开发和维护的官方 Kotlin 库,旨在提供高效、安全且易于使用的序列化框架。它不仅仅局限于 JSON,还支持 CBOR、Protobuf 等多种格式,并且是 Kotlin Multiplatform 项目的核心组成部分,能够实现跨平台(JVM, JS, Native)的代码共享。本文将聚焦于其在 JSON 序列化方面的应用,通过详细的讲解和实战示例,带你全面掌握 kotlinx.serialization 的使用。

为什么选择 Kotlinx.serialization?

在 Java 生态中,Jackson 和 Gson 是非常成熟且广泛使用的 JSON 库。那么,在 Kotlin 项目中,我们为什么应该考虑 kotlinx.serialization 呢?

  1. Kotlin 优先 (Kotlin-First): 它是专门为 Kotlin 设计的,能够充分利用 Kotlin 的语言特性,如数据类(Data Classes)、密封类(Sealed Classes)、默认参数、空安全(Null Safety)等,使得序列化代码更加简洁和地道。
  2. 编译时安全: 与依赖运行时反射的库(如 Gson 和 Jackson 的默认模式)不同,kotlinx.serialization 主要依赖 Kotlin 编译器插件在编译时生成序列化器(Serializer)。这减少了运行时的反射开销,提高了性能,并且能在编译阶段发现许多潜在的序列化错误,增强了类型安全性。
  3. 空安全集成: 深度集成了 Kotlin 的空安全系统。对于不可空类型,如果 JSON 中对应的字段缺失或为 null,反序列化会(默认)抛出异常,这符合 Kotlin 的设计哲学,有助于在早期捕获数据问题。
  4. 多平台支持 (Multiplatform): 作为 Kotlin Multiplatform 的核心库,kotlinx.serialization 可以在 JVM、JavaScript、Native(iOS, Linux, Windows, macOS 等)等多个平台上无缝工作,是构建跨平台应用的理想选择。
  5. 简洁的 API: 其 API 设计简洁直观,学习曲线相对平缓。
  6. 可扩展性: 支持自定义序列化器,可以轻松处理复杂类型或非标准格式。

基础入门:环境配置与基本使用

1. 添加依赖

首先,你需要在你的 Kotlin 项目(通常是 build.gradle.ktsbuild.gradle 文件)中添加 kotlinx.serialization 的依赖和编译器插件。

对于 Gradle Kotlin DSL (build.gradle.kts):

“`kotlin
plugins {
kotlin(“jvm”) version “1.8.20” // Or your Kotlin version
kotlin(“plugin.serialization”) version “1.8.20” // Use the same version as Kotlin
}

repositories {
mavenCentral()
}

dependencies {
implementation(“org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1”) // Use the latest stable version
// … other dependencies
}
“`

对于 Gradle Groovy DSL (build.gradle):

“`groovy
plugins {
id ‘org.jetbrains.kotlin.jvm’ version ‘1.8.20’ // Or your Kotlin version
id ‘org.jetbrains.kotlin.plugin.serialization’ version ‘1.8.20’ // Use the same version as Kotlin
}

repositories {
mavenCentral()
}

dependencies {
implementation ‘org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1’ // Use the latest stable version
// … other dependencies
}
“`

关键点:

  • kotlin("plugin.serialization")id 'org.jetbrains.kotlin.plugin.serialization':这是 Kotlin 编译器插件,负责在编译时为标记了 @Serializable 的类生成必要的序列化代码。必须添加此插件
  • kotlinx-serialization-json: 这是 kotlinx.serialization 针对 JSON 格式的具体实现库。如果你需要支持其他格式(如 Protobuf),需要添加对应的依赖。

2. 定义可序列化的数据类

要使一个类能够被 kotlinx.serialization 处理,你需要使用 @Serializable 注解标记它。通常,我们使用数据类(Data Class)来表示需要序列化的数据结构。

“`kotlin
import kotlinx.serialization.
import kotlinx.serialization.json.

@Serializable
data class User(
val id: Long,
val username: String,
val email: String?, // Nullable field
val isActive: Boolean = true // Field with default value
)
“`

  • @Serializable: 这个注解告诉编译器插件为 User 类生成序列化器。
  • 类及其所有需要序列化的属性(主构造函数中的)通常应该是 valvar
  • 支持 Kotlin 的空安全(email: String?)和默认参数值(isActive: Boolean = true)。

3. 序列化 (对象 -> JSON)

使用 Json 对象(kotlinx.serialization.json.Json)来执行序列化和反序列化操作。Json 类提供了 encodeToString 方法将对象转换为 JSON 字符串。

“`kotlin
import kotlinx.serialization.
import kotlinx.serialization.json.

@Serializable
data class User(
val id: Long,
val username: String,
val email: String?,
val isActive: Boolean = true
)

fun main() {
val user = User(id = 1, username = “kotlin_dev”, email = “dev@example.com”)
val userWithoutEmail = User(id = 2, username = “guest”, email = null, isActive = false)

// 使用默认配置的 Json 实例
val json = Json

// 序列化 user 对象
val userJsonString = json.encodeToString(user)
println("Serialized User 1: $userJsonString")
// Output: Serialized User 1: {"id":1,"username":"kotlin_dev","email":"dev@example.com","isActive":true}

// 序列化 userWithoutEmail 对象
val userWithoutEmailJsonString = json.encodeToString(userWithoutEmail)
println("Serialized User 2: $userWithoutEmailJsonString")
// Output: Serialized User 2: {"id":2,"username":"guest","email":null,"isActive":false}

// 注意:默认情况下,具有默认值的字段(如 isActive=true)也会被序列化。
// 如果想在值等于默认值时不序列化该字段,需要配置 Json 实例(后面会讲)。

}
“`

4. 反序列化 (JSON -> 对象)

同样使用 Json 对象,调用 decodeFromString 方法将 JSON 字符串转换回 Kotlin 对象。

“`kotlin
import kotlinx.serialization.
import kotlinx.serialization.json.

@Serializable
data class User(
val id: Long,
val username: String,
val email: String?,
val isActive: Boolean = true
)

fun main() {
val json = Json

val jsonString1 = """{"id":101,"username":"coder","email":"coder@example.com","isActive":true}"""
val jsonString2 = """{"id":102,"username":"tester","email":null}""" // "isActive" 缺失
val jsonString3 = """{"id":103,"username":"manager"}""" // "email" 和 "isActive" 都缺失

// 反序列化 jsonString1
val user1 = json.decodeFromString<User>(jsonString1)
println("Deserialized User 1: $user1")
// Output: Deserialized User 1: User(id=101, username=coder, email=coder@example.com, isActive=true)

// 反序列化 jsonString2
// "isActive" 字段缺失,但 User 类中该字段有默认值 true,所以反序列化成功
val user2 = json.decodeFromString<User>(jsonString2)
println("Deserialized User 2: $user2")
// Output: Deserialized User 2: User(id=102, username=tester, email=null, isActive=true)

// 反序列化 jsonString3
// "email" 字段缺失,但 User 类中该字段是可空的 (String?),所以反序列化成功,值为 null
// "isActive" 字段缺失,使用默认值 true
val user3 = json.decodeFromString<User>(jsonString3)
println("Deserialized User 3: $user3")
// Output: Deserialized User 3: User(id=103, username=manager, email=null, isActive=true)

// 尝试反序列化缺少非空且无默认值字段的 JSON
val invalidJsonString = """{"id":104, "email":"invalid@example.com"}""" // "username" 缺失
try {
    json.decodeFromString<User>(invalidJsonString)
} catch (e: SerializationException) {
    println("\nError deserializing invalid JSON: ${e.message}")
    // Output: Error deserializing invalid JSON: Field 'username' is required for type with serial name 'User', but it was missing at path: $
}

}
“`

这个例子展示了 kotlinx.serialization 如何优雅地处理 Kotlin 的空安全和默认参数:

  • 如果 JSON 中缺少字段,但 Kotlin 类中对应字段是可空的 (?),则反序列化为 null
  • 如果 JSON 中缺少字段,但 Kotlin 类中对应字段有默认值,则使用该默认值。
  • 如果 JSON 中缺少字段,而 Kotlin 类中对应字段既不可空也无默认值,则反序列化会抛出 MissingFieldExceptionSerializationException 的子类)。

处理常见数据结构

kotlinx.serialization 内建支持所有 Kotlin 基本类型、字符串、枚举,以及集合类型(List, Set, Map)和数组。

“`kotlin
import kotlinx.serialization.
import kotlinx.serialization.json.

@Serializable
enum class Role { ADMIN, USER, GUEST }

@Serializable
data class Project(
val name: String,
val priority: Int,
val tags: List,
val contributors: Map, // Map
val milestones: Set? = null // Nullable Set
)

@Serializable
data class User(val id: Long, val username: String) // Simplified User

fun main() {
val json = Json { prettyPrint = true } // 配置 Json 进行美化输出

val project = Project(
    name = "Kotlinx Serialization Demo",
    priority = 1,
    tags = listOf("kotlin", "serialization", "json"),
    contributors = mapOf(
        Role.ADMIN to User(1, "Alice"),
        Role.USER to User(2, "Bob")
    ),
    milestones = setOf("v1.0", "v1.1")
)

// 序列化
val projectJson = json.encodeToString(project)
println("Serialized Project:\n$projectJson")

// 反序列化
val deserializedProject = json.decodeFromString<Project>(projectJson)
println("\nDeserialized Project: $deserializedProject")

// 示例:处理包含 null 集合的 JSON
val jsonWithNullMilestones = """
{
    "name": "Another Project",
    "priority": 2,
    "tags": ["java", "legacy"],
    "contributors": {
        "GUEST": {"id": 3, "username": "Charlie"}
    },
    "milestones": null 
}
"""
val projectWithNullMilestones = json.decodeFromString<Project>(jsonWithNullMilestones)
println("\nDeserialized Project with null milestones: $projectWithNullMilestones")

// 示例:处理缺少可选集合的 JSON
val jsonWithoutMilestones = """
{
    "name": "Simple Project",
    "priority": 3,
    "tags": [],
    "contributors": {}
}
""" // milestones 字段缺失
val projectWithoutMilestones = json.decodeFromString<Project>(jsonWithoutMilestones)
println("\nDeserialized Project without milestones: $projectWithoutMilestones")
// Output: milestones will be null because the field in Project is nullable (? = null)

}

“`

输出分析:

  • List<String> 被序列化为 JSON 数组。
  • Map<Role, User> 被序列化为 JSON 对象,其中 Key (枚举 Role) 默认被序列化为其 name 字符串(”ADMIN”, “USER”)。
  • Set<String>? 被序列化为 JSON 数组,如果值为 null,则序列化为 JSON null
  • 反序列化时,也能正确地将 JSON 结构映射回 Kotlin 的集合类型和枚举。

高级特性与定制化

1. 自定义字段名称 (@SerialName)

有时,Kotlin 属性的命名规范(如 camelCase)与 JSON API 的规范(如 snake_case)不同。可以使用 @SerialName 注解来指定序列化和反序列化时使用的 JSON 字段名称。

“`kotlin
import kotlinx.serialization.
import kotlinx.serialization.json.

@Serializable
data class Product(
val productId: String, // Kotlin: camelCase
@SerialName(“product_name”) // JSON: snake_case
val productName: String,
@SerialName(“is_available”) // JSON: snake_case
val isAvailable: Boolean
)

fun main() {
val json = Json { prettyPrint = true }
val product = Product(“KF-123”, “Super Widget”, true)

// 序列化
val productJson = json.encodeToString(product)
println("Serialized Product:\n$productJson")
/* Output:
{
    "productId": "KF-123",
    "product_name": "Super Widget",
    "is_available": true
}
*/

// 反序列化
val jsonInput = """
{
    "productId": "KF-456",
    "product_name": "Mega Gadget",
    "is_available": false
}
"""
val deserializedProduct = json.decodeFromString<Product>(jsonInput)
println("\nDeserialized Product: $deserializedProduct")
// Output: Deserialized Product: Product(productId=KF-456, productName=Mega Gadget, isAvailable=false)

}
“`

2. 忽略字段 (@Transient)

如果希望某个属性不参与序列化和反序列化(例如,它是临时计算值或内部状态),可以使用 @Transient 注解(来自 kotlin.jvm.Transient,或者在多平台项目中使用 kotlinx.serialization.Transient)。

“`kotlin
import kotlinx.serialization.
import kotlinx.serialization.json.

import kotlin.jvm.Transient // For JVM projects

@Serializable
data class Report(
val id: Int,
val data: String,
@Transient val generationTimestamp: Long = System.currentTimeMillis() // This field will be ignored
)

fun main() {
val json = Json
val report = Report(1, “Some data”)
println(“Original Report: $report”) // Includes timestamp

// 序列化
val reportJson = json.encodeToString(report)
println("Serialized Report: $reportJson") // Excludes timestamp
// Output: Serialized Report: {"id":1,"data":"Some data"}

// 反序列化
val deserializedReport = json.decodeFromString<Report>(reportJson)
println("Deserialized Report: $deserializedReport") // Timestamp will have its default value (current time during deserialization)

}
``
注意:
@kotlinx.serialization.Transient是多平台兼容的注解,如果你在多平台项目中使用,推荐使用这个。@kotlin.jvm.Transient` 仅适用于 JVM 平台。

3. 显式标记非空字段为必需 (@Required) – (注意:行为已演变)

在早期版本的 kotlinx.serialization 中,@Required 注解用于强制要求 JSON 中必须存在某个字段,即使它在 Kotlin 类中有默认值。

然而,当前版本的推荐做法是
* 非空类型 + 无默认值: 字段是必需的。JSON 缺失会报错。
* 非空类型 + 有默认值: 字段是可选的。JSON 缺失会使用默认值。
* 可空类型 (?): 字段是可选的。JSON 缺失会反序列化为 null

@Required 注解现在主要用于在特殊情况下覆盖默认行为(例如,即使有默认值也强制要求字段存在),但大多数常见场景下不再需要显式使用它来表示“必需”。如果你需要一个字段必须存在于 JSON 中,只需将其声明为非空且不提供默认值即可。

“`kotlin
import kotlinx.serialization.
import kotlinx.serialization.json.

@Serializable
data class Configuration(
val host: String, // Required: Non-nullable, no default value
val port: Int = 8080, // Optional: Non-nullable, has default value
val apiKey: String? // Optional: Nullable
)

fun main() {
val json = Json { ignoreUnknownKeys = true } // Often useful

// Valid JSONs
val json1 = """{"host":"localhost", "port":9000, "apiKey":"abc"}"""
val json2 = """{"host":"192.168.1.1"}""" // port uses default, apiKey is null
val json3 = """{"host":"example.com", "port":80}""" // apiKey is null

println(json.decodeFromString<Configuration>(json1))
println(json.decodeFromString<Configuration>(json2))
println(json.decodeFromString<Configuration>(json3))

// Invalid JSON (missing required 'host')
val invalidJson = """{"port":8080, "apiKey":"xyz"}"""
try {
    json.decodeFromString<Configuration>(invalidJson)
} catch (e: SerializationException) {
    println("\nError: ${e.message}") // Output: Error: Field 'host' is required... but it was missing...
}

}
“`

4. 多态序列化 (Sealed Classes 和 Interfaces)

kotlinx.serialization 对 Kotlin 的密封类(Sealed Classes)提供了出色的多态序列化支持。当你需要序列化一个对象,而这个对象的具体类型是某个继承层次结构中的一个时,多态序列化就派上用场了。

“`kotlin
import kotlinx.serialization.
import kotlinx.serialization.json.

// Base sealed class marked as Serializable
@Serializable
sealed class Message {
abstract val id: String
}

// Subclass 1
@Serializable
@SerialName(“text_message”) // Explicit name for the type in JSON
data class TextMessage(override val id: String, val text: String) : Message()

// Subclass 2
@Serializable
@SerialName(“image_message”)
data class ImageMessage(override val id: String, val imageUrl: String) : Message()

// A class containing a list of messages
@Serializable
data class Chat(val chatId: String, val messages: List)

fun main() {
// Configure Json to handle polymorphism using the default “type” discriminator
val json = Json {
prettyPrint = true
// For polymorphism with sealed/open classes, kotlinx.serialization needs
// to know how to determine the actual type during deserialization.
// It does this using a ‘class discriminator’ property.
// The default discriminator is “type”.
// You can customize it via classDiscriminator = "your_discriminator_name"
// If subclasses use @SerialName, that name is used as the value for the discriminator.
// Otherwise, the fully qualified class name is used.
}

val chat = Chat(
    chatId = "chat-123",
    messages = listOf(
        TextMessage("msg-1", "Hello Kotlin!"),
        ImageMessage("msg-2", "http://example.com/image.png")
    )
)

// Serialize the Chat object containing polymorphic messages
val chatJson = json.encodeToString(chat)
println("Serialized Chat:\n$chatJson")
/* Output:
{
    "chatId": "chat-123",
    "messages": [
        {
            "type": "text_message", // Discriminator added automatically
            "id": "msg-1",
            "text": "Hello Kotlin!"
        },
        {
            "type": "image_message", // Discriminator based on @SerialName
            "id": "msg-2",
            "imageUrl": "http://example.com/image.png"
        }
    ]
}
*/

// Deserialize the JSON back into the Chat object
val deserializedChat = json.decodeFromString<Chat>(chatJson)
println("\nDeserialized Chat: $deserializedChat")
println("First message type: ${deserializedChat.messages[0]::class.simpleName}") // TextMessage
println("Second message type: ${deserializedChat.messages[1]::class.simpleName}") // ImageMessage

}
“`

关键点:

  • 基类(Message)必须标记为 @Serializable
  • 所有子类(TextMessage, ImageMessage)也必须标记为 @Serializable
  • kotlinx.serialization 会在序列化时自动添加一个类鉴别器(Class Discriminator)字段(默认为 "type"),其值为子类的序列化名称(由 @SerialName 指定或默认为类全名)。
  • 反序列化时,库根据鉴别器字段的值来确定应该创建哪个子类的实例。
  • 可以通过 Json { classDiscriminator = "..." } 来自定义鉴别器字段的名称。

对于接口(Interface)或开放类(Open Class)的多态,配置稍微复杂一些,通常需要显式注册子类到序列化模块 (SerializersModule) 中。

5. 自定义序列化器 (KSerializer<T>)

当内建的序列化逻辑不满足需求时(例如,需要处理不支持的类型如 java.util.Date,或者需要特定的 JSON 格式),可以创建自定义序列化器。

实现 KSerializer<T> 接口,并重写 descriptorserializedeserialize 方法。

“`kotlin
import kotlinx.serialization.
import kotlinx.serialization.encoding.

import kotlinx.serialization.descriptors.
import kotlinx.serialization.json.

import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

// Custom Serializer for java.util.Date using ISO 8601 format
object DateAsIso8601StringSerializer : KSerializer {
// Use a thread-safe formatter if needed in concurrent environments
private val dateFormat = SimpleDateFormat(“yyyy-MM-dd’T’HH:mm:ss’Z'”, Locale.US).apply {
timeZone = java.util.TimeZone.getTimeZone(“UTC”)
}

override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING)

override fun serialize(encoder: Encoder, value: Date) {
    encoder.encodeString(dateFormat.format(value))
}

override fun deserialize(decoder: Decoder): Date {
    return dateFormat.parse(decoder.decodeString())
}

}

@Serializable
data class Event(
val eventName: String,
@Serializable(with = DateAsIso8601StringSerializer::class) // Apply the custom serializer
val eventTime: Date
)

fun main() {
val json = Json { prettyPrint = true }
val event = Event(“System Startup”, Date()) // Current time

// Serialize
val eventJson = json.encodeToString(event)
println("Serialized Event:\n$eventJson")
/* Output (example):
{
    "eventName": "System Startup",
    "eventTime": "2023-10-27T10:30:00Z"
}
*/

// Deserialize
val jsonInput = """
{
    "eventName": "User Login",
    "eventTime": "2023-10-27T11:00:00Z"
}
"""
val deserializedEvent = json.decodeFromString<Event>(jsonInput)
println("\nDeserialized Event: $deserializedEvent")

}
“`

应用自定义序列化器的方式:

  • @Serializable(with = ...): 直接在属性或类上注解,指定使用的序列化器。
  • @Contextual: 标记属性或类,表示序列化器将在运行时通过上下文(SerializersModule)提供。这对于无法直接注解的第三方类很有用。
  • SerializersModule: 在配置 Json 实例时,通过 serializersModule 提供类型和自定义序列化器的映射。

6. 配置 Json 实例

Json 对象可以通过一个配置块(lambda)进行定制,以改变其行为。

“`kotlin
val customJson = Json {
prettyPrint = true // 输出格式化的 JSON 字符串
isLenient = true // 允许非标准的 JSON 格式(如 unquoted keys/strings),谨慎使用
ignoreUnknownKeys = true // 反序列化时忽略 JSON 中存在但 Kotlin 类中没有的字段
encodeDefaults = false // 不序列化值等于其默认值的属性
allowStructuredMapKeys = true // 允许 Map 的 Key 是复杂对象(序列化为 JSON 字符串)
classDiscriminator = “#type” // 自定义多态鉴别器名称
// serializersModule = … // 注册上下文序列化器或多态子类
}

// — Example using encodeDefaults = false —
@Serializable
data class Config(val timeout: Int = 5000, val retries: Int = 3)

val config = Config() // Uses default values
val jsonDefault = Json // Default configuration
val jsonSkipDefaults = Json { encodeDefaults = false }

println(“Default encoding: ${jsonDefault.encodeToString(config)}”)
// Output: Default encoding: {“timeout”:5000,”retries”:3}

println(“Skip defaults encoding: ${jsonSkipDefaults.encodeToString(config)}”)
// Output: Skip defaults encoding: {}

val configCustom = Config(timeout = 10000) // ‘retries’ still default
println(“Skip defaults encoding (custom): ${jsonSkipDefaults.encodeToString(configCustom)}”)
// Output: Skip defaults encoding (custom): {“timeout”:10000}
“`

常用的配置选项:

  • prettyPrint: 美化输出,增加缩进和换行,便于阅读。
  • ignoreUnknownKeys: 提高健壮性。当 API 返回了新的字段,而你的代码还没更新时,设置 true 可以避免反序列化失败。
  • encodeDefaults: 控制是否序列化那些值等于其在类定义中声明的默认值的属性。false 可以减小 JSON 体积。
  • isLenient: 放宽对 JSON 格式的要求,允许一些不严格符合 RFC 8259 标准的写法。一般不推荐在生产环境随意开启。
  • classDiscriminator: 用于多态序列化的类型标识字段名。

错误处理

反序列化是容易出错的操作,输入的 JSON 可能格式错误、缺少必需字段或包含类型不匹配的值。kotlinx.serialization 会在遇到这些问题时抛出 SerializationException 或其子类(如 MissingFieldException, UnknownKeyException)。务必使用 try-catch 块来处理这些潜在的异常。

“`kotlin
val json = Json { ignoreUnknownKeys = false } // Explicitly disable ignoring unknown keys

fun deserializeUserSafe(jsonString: String): User? {
return try {
json.decodeFromString(jsonString)
} catch (e: SerializationException) {
println(“Failed to deserialize: ${e.message}”)
null // Return null or handle error appropriately
} catch (e: IllegalArgumentException) {
// Catch potential errors from custom serializers or lenient parsing
println(“Invalid input format: ${e.message}”)
null
}
}

// Example Usage
val validJson = “””{“id”:1,”username”:”valid”,”email”:”valid@example.com”}”””
val invalidJsonMissingField = “””{“id”:2,”email”:null}””” // Missing ‘username’
val invalidJsonUnknownField = “””{“id”:3,”username”:”unknown”,”extraField”:true}”””
val malformedJson = “””{“id”:4, username:”malformed”}””” // Unquoted key/string (requires lenient=true)

deserializeUserSafe(validJson)
deserializeUserSafe(invalidJsonMissingField) // Prints error: Field ‘username’ is required…
deserializeUserSafe(invalidJsonUnknownField) // Prints error: Unknown key ‘extraField’…
deserializeUserSafe(malformedJson) // Prints error: Expected quotation mark… (if isLenient=false)
“`

性能考量

由于 kotlinx.serialization 依赖编译器插件在编译时生成适配代码,它通常比依赖运行时反射的库(如 Gson 或 Jackson 的默认模式)具有更好的启动性能和运行时性能。生成的代码是直接的 Kotlin/Java 代码,避免了反射调用开销。对于性能敏感的应用或 Android 这类启动时间很关键的平台,这可以是一个显著的优势。当然,对于非常复杂的对象图或极高的吞吐量需求,具体的性能表现还需要通过基准测试来衡量。

总结

kotlinx.serialization 是 Kotlin 生态中用于数据序列化的强大而现代的解决方案。它凭借与 Kotlin 语言特性的深度集成(尤其是数据类、空安全和密封类)、编译时安全性、多平台支持以及简洁的 API,为 Kotlin 开发者提供了处理 JSON(及其他格式)的卓越体验。

通过本文的介绍和示例,你应该已经掌握了使用 kotlinx.serialization 进行 JSON 序列化和反序列化的基本方法,以及如何利用其高级特性(如自定义字段名、忽略字段、多态处理、自定义序列化器和 Json 配置)来满足各种实际需求。在你的下一个 Kotlin 项目中,无论是构建后端服务、Android/iOS 应用还是跨平台库,都强烈推荐尝试并使用 kotlinx.serialization,体验 Kotlin 原生的序列化能力。


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注