Skip to Content

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ệnMultiplatformKotlin-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

AnnotationMục đích
@SerializableĐánh dấu class có thể serialize
@SerialNameCustom field name trong JSON
@TransientBỏ qua field khi serialize
@RequiredField bắt buộc phải có
@EncodeDefaultEncode cả default values

Best Practices

  1. Luôn dùng ignoreUnknownKeys = true khi parse API response
  2. Dùng default values cho optional fields
  3. Tạo custom Json instance thay vì dùng Json mặc định
  4. 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