欢迎访问我的主页: https://heeheeaii.github.io/
1. 基础配置
项目配置
kotlin
// build.gradle.kts (Module)
plugins {
kotlin("jvm") version "1.9.10"
kotlin("plugin.serialization") version "1.9.10"
}
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
}
基本使用
kotlin
import kotlinx.serialization.*
import kotlinx.serialization.json.*
@Serializable
data class User(
val id: Int,
val name: String,
val email: String
)
fun main() {
val user = User(1, "张三", "zhangsan@example.com")
// 序列化:对象 → JSON 字符串
val jsonString = Json.encodeToString(user)
println(jsonString)
// {"id":1,"name":"张三","email":"zhangsan@example.com"}
// 反序列化:JSON 字符串 → 对象
val decodedUser = Json.decodeFromString<User>(jsonString)
println(decodedUser)
// User(id=1, name=张三, email=zhangsan@example.com)
}
2. 字段映射和配置
@SerialName - 字段名映射
kotlin
@Serializable
data class User(
val id: Int,
@SerialName("user_name")
val name: String,
@SerialName("email_address")
val email: String,
@SerialName("created_at")
val createdAt: String
)
fun testSerialName() {
val user = User(1, "张三", "zhang@example.com", "2023-01-01")
val json = Json.encodeToString(user)
println(json)
// {"id":1,"user_name":"张三","email_address":"zhang@example.com","created_at":"2023-01-01"}
}
可选字段和默认值
kotlin
@Serializable
data class Product(
val id: Int,
val name: String,
val price: Double,
val description: String? = null, // 可为空
val category: String = "未分类", // 默认值
val isActive: Boolean = true
)
fun testDefaultValues() {
// JSON 中缺少某些字段
val json = """{"id":1,"name":"iPhone","price":999.99}"""
val product = Json.decodeFromString<Product>(json)
println(product)
// Product(id=1, name=iPhone, price=999.99, description=null, category=未分类, isActive=true)
}
@Transient - 忽略字段
kotlin
@Serializable
data class User(
val id: Int,
val name: String,
@Transient
val password: String = "", // 不会被序列化
@Transient
val tempData: Map<String, Any> = emptyMap()
)
fun testTransient() {
val user = User(1, "张三", "secret123", mapOf("cache" to "data"))
val json = Json.encodeToString(user)
println(json)
// {"id":1,"name":"张三"} // password 和 tempData 被忽略
}
3. 集合和复杂类型
基本集合
kotlin
@Serializable
data class UserList(
val users: List<User>,
val tags: Set<String>,
val metadata: Map<String, String>
)
fun testCollections() {
val userList = UserList(
users = listOf(
User(1, "张三", "zhang@example.com"),
User(2, "李四", "li@example.com")
),
tags = setOf("admin", "user"),
metadata = mapOf("total" to "2", "page" to "1")
)
val json = Json.encodeToString(userList)
println(Json { prettyPrint = true }.encodeToString(userList))
}
// 直接序列化集合
fun testDirectCollections() {
val users = listOf(
User(1, "张三", "zhang@example.com"),
User(2, "李四", "li@example.com")
)
// List<User> 直接序列化
val json = Json.encodeToString(users)
println(json)
// 反序列化为 List<User>
val decodedUsers = Json.decodeFromString<List<User>>(json)
println(decodedUsers)
}
嵌套对象
kotlin
@Serializable
data class Address(
val street: String,
val city: String,
val zipCode: String
)
@Serializable
data class Company(
val id: Int,
val name: String,
val address: Address, // 嵌套对象
val employees: List<User> // 嵌套列表
)
fun testNestedObjects() {
val company = Company(
id = 1,
name = "科技有限公司",
address = Address("中关村大街1号", "北京", "100000"),
employees = listOf(
User(1, "张三", "zhang@example.com"),
User(2, "李四", "li@example.com")
)
)
val json = Json { prettyPrint = true }.encodeToString(company)
println(json)
}
4. 多态序列化
密封类 (Sealed Class)
kotlin
@Serializable
sealed class ApiResponse {
@Serializable
@SerialName("success")
data class Success(val data: String, val timestamp: Long) : ApiResponse()
@Serializable
@SerialName("error")
data class Error(val message: String, val code: Int) : ApiResponse()
@Serializable
@SerialName("loading")
object Loading : ApiResponse()
}
fun testPolymorphism() {
val responses: List<ApiResponse> = listOf(
ApiResponse.Success("数据获取成功", System.currentTimeMillis()),
ApiResponse.Error("网络错误", 500),
ApiResponse.Loading
)
// 序列化多态对象
val json = Json { prettyPrint = true }.encodeToString(responses)
println(json)
// 反序列化
val decodedResponses = Json.decodeFromString<List<ApiResponse>>(json)
decodedResponses.forEach { response ->
when (response) {
is ApiResponse.Success -> println("成功: ${response.data}")
is ApiResponse.Error -> println("错误: ${response.message}")
is ApiResponse.Loading -> println("加载中...")
}
}
}
抽象类多态
kotlin
@Serializable
@JsonClassDiscriminator("type")
abstract class Shape
@Serializable
@SerialName("circle")
data class Circle(val radius: Double) : Shape()
@Serializable
@SerialName("rectangle")
data class Rectangle(val width: Double, val height: Double) : Shape()
@Serializable
@SerialName("triangle")
data class Triangle(val base: Double, val height: Double) : Shape()
fun testAbstractPolymorphism() {
val shapes: List<Shape> = listOf(
Circle(5.0),
Rectangle(10.0, 8.0),
Triangle(6.0, 4.0)
)
val json = Json { prettyPrint = true }.encodeToString(shapes)
println(json)
val decodedShapes = Json.decodeFromString<List<Shape>>(json)
println(decodedShapes)
}
5. 自定义序列化器
日期时间序列化
kotlin
@Serializable
data class Event(
val id: Int,
val name: String,
@Serializable(with = DateTimeSerializer::class)
val createdAt: LocalDateTime
)
object DateTimeSerializer : KSerializer<LocalDateTime> {
private val formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME
override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor("LocalDateTime", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: LocalDateTime) {
encoder.encodeString(value.format(formatter))
}
override fun deserialize(decoder: Decoder): LocalDateTime {
return LocalDateTime.parse(decoder.decodeString(), formatter)
}
}
fun testCustomSerializer() {
val event = Event(1, "会议", LocalDateTime.now())
val json = Json.encodeToString(event)
println(json)
val decodedEvent = Json.decodeFromString<Event>(json)
println(decodedEvent)
}
枚举序列化
kotlin
@Serializable
enum class Status(val value: String) {
@SerialName("active") ACTIVE("激活"),
@SerialName("inactive") INACTIVE("未激活"),
@SerialName("pending") PENDING("待审核");
@Serializer(forClass = Status::class)
companion object : KSerializer<Status> {
override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor("Status", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: Status) {
encoder.encodeString(value.name.lowercase())
}
override fun deserialize(decoder: Decoder): Status {
val name = decoder.decodeString().uppercase()
return Status.valueOf(name)
}
}
}
@Serializable
data class User(
val id: Int,
val name: String,
val status: Status
)
BigDecimal 序列化器
kotlin
object BigDecimalSerializer : KSerializer<BigDecimal> {
override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor("BigDecimal", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: BigDecimal) {
encoder.encodeString(value.toPlainString())
}
override fun deserialize(decoder: Decoder): BigDecimal {
return BigDecimal(decoder.decodeString())
}
}
@Serializable
data class Product(
val id: Int,
val name: String,
@Serializable(with = BigDecimalSerializer::class)
val price: BigDecimal
)
6. Json 配置选项
常用配置
kotlin
val json = Json {
// 忽略 JSON 中未知的字段
ignoreUnknownKeys = true
// 美化输出
prettyPrint = true
// 类型强制转换 (如字符串 "1" 转为数字 1)
coerceInputValues = true
// 编码默认值
encodeDefaults = true
// 允许结构化键 (Map 的键可以是复杂对象)
allowStructuredMapKeys = true
// 允许特殊浮点值 (NaN, Infinity)
allowSpecialFloatingPointValues = true
}
@Serializable
data class Config(
val name: String,
val age: Int = 18,
val isActive: Boolean = true
)
fun testJsonConfig() {
val config = Config("测试")
// 使用配置的 Json 实例
val jsonString = json.encodeToString(config)
println(jsonString)
// 解析包含未知字段的 JSON
val jsonWithExtra = """
{
"name": "测试",
"age": "25",
"isActive": true,
"unknownField": "这个字段会被忽略"
}
""".trimIndent()
val decoded = json.decodeFromString<Config>(jsonWithExtra)
println(decoded)
// Config(name=测试, age=25, isActive=true)
}
自定义命名策略
kotlin
// 使用自定义命名策略
val snakeCaseJson = Json {
namingStrategy = JsonNamingStrategy.SnakeCase
}
@Serializable
data class UserProfile(
val userId: Int,
val firstName: String,
val lastName: String,
val emailAddress: String
)
fun testNamingStrategy() {
val profile = UserProfile(1, "张", "三", "zhangsan@example.com")
val json = snakeCaseJson.encodeToString(profile)
println(json)
// {"user_id":1,"first_name":"张","last_name":"三","email_address":"zhangsan@example.com"}
}
7. 错误处理和验证
异常处理
kotlin
fun safeDeserialization() {
val invalidJson = """{"id": "not_a_number", "name": "张三"}"""
try {
val user = Json.decodeFromString<User>(invalidJson)
println(user)
} catch (e: SerializationException) {
println("序列化错误: ${e.message}")
// 可以提供默认值或其他处理逻辑
}
}
// 更优雅的错误处理
fun safeParseUser(jsonString: String): Result<User> {
return try {
Result.success(Json.decodeFromString<User>(jsonString))
} catch (e: SerializationException) {
Result.failure(e)
}
}
条件序列化
kotlin
@Serializable
data class ConditionalUser(
val id: Int,
val name: String,
@EncodeDefault(EncodeDefault.Mode.NEVER) // 从不编码默认值
val role: String = "user",
@EncodeDefault(EncodeDefault.Mode.ALWAYS) // 总是编码默认值
val isActive: Boolean = true
)
8. 与网络库集成
与 OkHttp + Retrofit 集成
kotlin
// Retrofit 配置
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(
Json.asConverterFactory("application/json".toMediaType())
)
.client(okHttpClient)
.build()
// API 接口
interface ApiService {
@GET("users/{id}")
suspend fun getUser(@Path("id") id: Int): User
@POST("users")
suspend fun createUser(@Body user: User): User
@GET("users")
suspend fun getUsers(): List<User>
}
与 Ktor Client 集成
kotlin
val client = HttpClient {
install(ContentNegotiation) {
json(Json {
prettyPrint = true
ignoreUnknownKeys = true
})
}
}
// 使用
suspend fun fetchUser(id: Int): User {
return client.get("https://api.example.com/users/$id").body()
}
suspend fun createUser(user: User): User {
return client.post("https://api.example.com/users") {
contentType(ContentType.Application.Json)
setBody(user)
}.body()
}
9. 实际应用示例
API 响应包装
kotlin
@Serializable
data class ApiResponse<T>(
val code: Int,
val message: String,
val data: T? = null,
val timestamp: Long = System.currentTimeMillis()
)
@Serializable
data class PaginatedResponse<T>(
val items: List<T>,
val total: Int,
val page: Int,
val pageSize: Int,
val hasNext: Boolean
)
// 使用示例
suspend fun fetchUsers(page: Int = 1): ApiResponse<PaginatedResponse<User>> {
val json = """
{
"code": 200,
"message": "success",
"data": {
"items": [
{"id": 1, "name": "张三", "email": "zhang@example.com"},
{"id": 2, "name": "李四", "email": "li@example.com"}
],
"total": 100,
"page": 1,
"pageSize": 10,
"hasNext": true
},
"timestamp": 1635724800000
}
""".trimIndent()
return Json.decodeFromString<ApiResponse<PaginatedResponse<User>>>(json)
}
配置文件处理
kotlin
@Serializable
data class AppConfig(
val server: ServerConfig,
val database: DatabaseConfig,
val logging: LoggingConfig
)
@Serializable
data class ServerConfig(
val host: String = "localhost",
val port: Int = 8080,
val ssl: Boolean = false
)
@Serializable
data class DatabaseConfig(
val url: String,
val username: String,
val password: String,
val maxConnections: Int = 10
)
@Serializable
data class LoggingConfig(
val level: String = "INFO",
val file: String? = null
)
// 从文件读取配置
fun loadConfig(configFile: File): AppConfig {
val json = configFile.readText()
return Json.decodeFromString<AppConfig>(json)
}
// 保存配置到文件
fun saveConfig(config: AppConfig, configFile: File) {
val json = Json { prettyPrint = true }.encodeToString(config)
configFile.writeText(json)
}
10. 最佳实践总结
1. 注解使用
kotlin
@Serializable
data class BestPracticeUser(
val id: Int,
// 使用 SerialName 映射 API 字段名
@SerialName("user_name")
val name: String,
// 可选字段设置默认值
val email: String? = null,
// 敏感信息不序列化
@Transient
val password: String = "",
// 自定义序列化器处理复杂类型
@Serializable(with = DateTimeSerializer::class)
val createdAt: LocalDateTime,
// 默认值处理
val role: String = "user",
val isActive: Boolean = true
)
2. 全局 Json 配置
kotlin
object JsonConfig {
val default = Json {
ignoreUnknownKeys = true
coerceInputValues = true
encodeDefaults = false
prettyPrint = BuildConfig.DEBUG // 仅在 Debug 模式下格式化
}
}
// 在整个应用中使用统一配置
val user = JsonConfig.default.decodeFromString<User>(jsonString)
3. 错误处理
kotlin
inline fun <reified T> String.parseJson(): Result<T> {
return try {
Result.success(Json.decodeFromString<T>(this))
} catch (e: SerializationException) {
Result.failure(e)
}
}
// 使用
val result = jsonString.parseJson<User>()
result.fold(
onSuccess = { user -> println("解析成功: $user") },
onFailure = { error -> println("解析失败: ${error.message}") }
)