Kotlin Serialization
Kotlin Serialization là thư viện chính thức để serialize/deserialize dữ liệu trong Kotlin Multiplatform.
Tại sao cần Kotlin Serialization?
| Thư viện | Multiplatform | Kotlin-first |
|---|---|---|
| Kotlin Serialization | ✅ | ✅ |
| Gson | ❌ Android only | ❌ Java |
| Moshi | ❌ JVM only | ⚠️ Partial |
| Jackson | ❌ JVM only | ❌ Java |
Bước 1: Thêm Dependencies
libs.versions.toml
[versions]
kotlin = "2.0.0"
kotlinx-serialization = "1.6.3"
[plugins]
kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
[libraries]
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }shared/build.gradle.kts
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.kotlinx.serialization) // Thêm plugin
}
kotlin {
sourceSets {
commonMain.dependencies {
implementation(libs.kotlinx.serialization.json)
}
}
}Bước 2: Tạo Data Classes
Cơ bản
import kotlinx.serialization.Serializable
@Serializable
data class User(
val id: Int,
val name: String,
val email: String
)Với custom field names
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class User(
val id: Int,
@SerialName("full_name") // JSON field name khác
val name: String,
@SerialName("email_address")
val email: String,
val age: Int = 0 // Default value
)Nested objects
@Serializable
data class Post(
val id: Int,
val title: String,
val author: User, // Nested object
val tags: List<String> // List
)Bước 3: Serialize và Deserialize
Object → JSON String
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
val user = User(1, "John", "john@example.com")
val jsonString = Json.encodeToString(user)
// {"id":1,"name":"John","email":"john@example.com"}JSON String → Object
import kotlinx.serialization.decodeFromString
val jsonString = """{"id":1,"name":"John","email":"john@example.com"}"""
val user = Json.decodeFromString<User>(jsonString)List of objects
val users = listOf(
User(1, "John", "john@example.com"),
User(2, "Jane", "jane@example.com")
)
val jsonArray = Json.encodeToString(users)
val parsedUsers = Json.decodeFromString<List<User>>(jsonArray)Bước 4: Custom Json Configuration
val json = Json {
// Pretty print với indentation
prettyPrint = true
// Bỏ qua fields không có trong data class
ignoreUnknownKeys = true
// Cho phép trailing comma, comments
isLenient = true
// Encode default values
encodeDefaults = true
// Cho phép special float values (NaN, Infinity)
allowSpecialFloatingPointValues = true
// Không fail khi gặp null cho non-null field
coerceInputValues = true
}
// Sử dụng custom json
val user = json.decodeFromString<User>(jsonString)Bước 5: Optional và Nullable Fields
@Serializable
data class Profile(
val id: Int,
val name: String,
val bio: String? = null, // Nullable với default null
val age: Int = 0, // Optional với default value
val isVerified: Boolean = false
)
// JSON không cần có tất cả fields
val json = """{"id":1,"name":"John"}"""
val profile = Json.decodeFromString<Profile>(json)
// Profile(id=1, name=John, bio=null, age=0, isVerified=false)Bước 6: Enum Classes
@Serializable
enum class UserRole {
ADMIN,
MODERATOR,
USER
}
@Serializable
data class User(
val id: Int,
val name: String,
val role: UserRole
)
val json = """{"id":1,"name":"John","role":"ADMIN"}"""
val user = Json.decodeFromString<User>(json)Custom enum serialization
@Serializable
enum class Status(val value: String) {
@SerialName("active") ACTIVE("active"),
@SerialName("inactive") INACTIVE("inactive"),
@SerialName("pending") PENDING("pending")
}Bước 7: Sealed Classes
@Serializable
sealed class NetworkResult {
@Serializable
@SerialName("success")
data class Success(val data: String) : NetworkResult()
@Serializable
@SerialName("error")
data class Error(val message: String) : NetworkResult()
}
// JSON với type discriminator
val successJson = """{"type":"success","data":"Hello"}"""
val errorJson = """{"type":"error","message":"Not found"}"""Bước 8: Custom Serializers
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
// Custom serializer cho Date
object DateSerializer : KSerializer<Long> {
override val descriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: Long) {
// Convert timestamp to ISO string
encoder.encodeString(value.toString())
}
override fun deserialize(decoder: Decoder): Long {
return decoder.decodeString().toLong()
}
}
@Serializable
data class Event(
val name: String,
@Serializable(with = DateSerializer::class)
val timestamp: Long
)Ví dụ thực tế: API Response
@Serializable
data class ApiResponse<T>(
val status: String,
val data: T?,
val error: ErrorInfo? = null
)
@Serializable
data class ErrorInfo(
val code: Int,
val message: String
)
@Serializable
data class UserListResponse(
val users: List<User>,
val total: Int,
val page: Int
)
// Sử dụng
val json = Json { ignoreUnknownKeys = true }
suspend fun parseUserResponse(jsonString: String): List<User> {
val response = json.decodeFromString<ApiResponse<UserListResponse>>(jsonString)
return response.data?.users ?: emptyList()
}📝 Tóm tắt
| Annotation | Mục đích |
|---|---|
@Serializable | Đánh dấu class có thể serialize |
@SerialName | Custom field name trong JSON |
@Transient | Bỏ qua field khi serialize |
@Required | Field bắt buộc phải có |
@EncodeDefault | Encode cả default values |
Best Practices
- Luôn dùng
ignoreUnknownKeys = truekhi parse API response - Dùng default values cho optional fields
- Tạo custom
Jsoninstance thay vì dùngJsonmặc định - Dùng
@SerialNameđể map với API field names
Tiếp theo
Học về SQLDelight để lưu trữ dữ liệu local trong KMP.
Last updated on