Giải tuần tự hóa: khái niệm, quy trình khôi phục dữ liệu

Tác giả: IT Sectr Đã đăng: 2026-03-08 Thời gian đọc: 9 phút

Giải tuần tự hóa là quá trình khôi phục một đối tượng từ luồng dữ liệu JSON, XML hoặc Protobuf, cần thiết cho bất kỳ ứng dụng di động nào làm việc với API từ xa. Theo Apple Developer (2026), xử lý dữ liệu đến không đúng cách vẫn là một trong những nguyên nhân phổ biến gây lỗi trên thiết bị. JSONDecoder trên iOS và Gson trên Android là các công cụ tiêu chuẩn, nhưng mỗi công cụ đều có đặc điểm và giới hạn riêng.

Những điểm chính

  • Giải tuần tự hóa là khôi phục một đối tượng đã được định kiểu từ JSON, XML hoặc Protobuf để sử dụng trong mã.
  • Codable là giao thức của Apple để giải tuần tự hóa tự động trong Swift với hỗ trợ tạo mã.
  • Moshi là thư viện Android từ Square với các tùy chọn codegen và reflection cho các tình huống khác nhau.
  • Type mismatch là lỗi phổ biến nhất khi kiểu trường JSON và thuộc tính mô hình không khớp.
  • kotlinx.serialization là giải pháp chính thức của JetBrains với tạo mã an toàn bởi trình biên dịch.

Giải tuần tự hóa là gì?

Giải tuần tự hóa là quá trình chuyển đổi một luồng byte hoặc văn bản có cấu trúc thành một đối tượng ngôn ngữ lập trình. Trong phát triển di động, quá trình này xảy ra mỗi khi ứng dụng nhận được phản hồi từ máy chủ: một chuỗi JSON biến thành một thể hiện của lớp User, Order hoặc Product. Sự ổn định của các màn hình hiển thị dữ liệu cho người dùng phụ thuộc trực tiếp vào tính chính xác của giải tuần tự hóa.

Khác biệt với tuần tự hóa

Tuần tự hóa và giải tuần tự hóa là hai quá trình nghịch đảo lẫn nhau, hiếm khi đối xứng trong thực tế. Tuần tự hóa chuyển đổi một đối tượng thành chuỗi để gửi đến máy chủ, trong khi giải tuần tự hóa khôi phục đối tượng từ chuỗi nhận được. Máy chủ có thể gửi một trường không tồn tại trong mô hình máy khách, sử dụng định dạng ngày khác hoặc trả về null thay vì một số. Theo Square Engineering (2025), sự bất đối xứng định dạng gây ra 23% lỗi lớp mạng trong ứng dụng Android. Để giảm rủi ro, việc quản lý phiên bản lược đồ và đặc tả hợp đồng nghiêm ngặt thông qua OpenAPI được sử dụng.

Các định dạng dữ liệu cho giải tuần tự hóa

JSON vẫn là định dạng phổ biến nhất cho API di động nhờ khả năng đọc được và hỗ trợ tích hợp. Protobuf của Google được sử dụng trong các hệ thống tải cao — nó nhỏ gọn hơn JSON 3-6 lần và phân tích nhanh hơn, nhưng yêu cầu tạo mã từ tệp .proto và không thể đọc nếu không có công cụ. XML ít phổ biến hơn trong các ứng dụng di động hiện đại, nhưng được sử dụng trong các dịch vụ SOAP của hệ thống doanh nghiệp và tệp cấu hình Android. MessagePack là một định dạng nhị phân tương tự JSON về cấu trúc nhưng nhỏ gọn hơn, phổ biến trong các hệ thống thời gian thực.

Cách thức hoạt động của giải tuần tự hóa

Quá trình giải tuần tự hóa trải qua ba giai đoạn. Đầu tiên, token hóa chia văn bản thô thành các token: khóa, chuỗi, số và dấu phân cách. Sau đó, phân tích cú pháp kiểm tra tính đúng đắn của cấu trúc — dấu ngoặc đã đóng chưa, loại dấu ngoặc kép có đúng không, định dạng có tuân thủ RFC 8259 không. Giai đoạn cuối cùng là ánh xạ sang mô hình đối tượng của ứng dụng, nơi mỗi khóa JSON được gán một thuộc tính lớp có xem xét chiến lược đặt tên.

Reflection vs Code generation

Hai cách tiếp cận ánh xạ đã xuất hiện trong phát triển di động. Reflection (Gson, JSONSerialization) phân tích cấu trúc lớp tại thời gian chạy qua Java Reflection API hoặc Objective-C runtime — linh hoạt và không yêu cầu cấu hình thêm, nhưng chậm hơn và tiêu tốn nhiều bộ nhớ hơn. Code generation (Moshi codegen, kotlinx.serialization, Codable) tạo mã tại thời gian biên dịch: nhanh hơn, an toàn về kiểu và không tiết lộ cấu trúc nội bộ qua reflection. JetBrains và Square khuyến nghị code generation cho các bản dựng sản xuất — hiệu suất tăng 2-4 lần trong các điểm chuẩn của Google.

swift
struct User: Codable {
    let id: Int
    let name: String
    let email: String
    let createdAt: Date
}

let json = """
{
    "id": 42,
    "name": "Alice",
    "email": "alice@example.com",
    "created_at": "2026-06-01T12:00:00Z"
}
"""
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let user = try decoder.decode(User.self, from: data)

Ví dụ về giải tuần tự hóa JSON thành mô hình User trong Swift. Chiến lược convertFromSnakeCase tự động chuyển đổi khóa API snake_case thành thuộc tính mô hình camelCase — một thông lệ tiêu chuẩn trong các dự án iOS. Tham số data là byte thô của phản hồi máy chủ nhận được qua URLSession. Xử lý lỗi qua try cho phép bắt JSON không đúng định dạng mà không làm ứng dụng bị lỗi.

Vai trò của các chiến lược giải mã

JSONDecoder hỗ trợ bốn chiến lược khóa: useDefaultKeys (khớp chính xác), convertFromSnakeCase (snake_case → camelCase), custom (closure) và convertFromKebabCase (kebab-case → camelCase). Cho ngày tháng, .iso8601, .secondsSince1970, .millisecondsSince1970 và dateFormatter tùy chỉnh có sẵn. Chọn đúng chiến lược là bước đầu tiên hướng tới giải tuần tự hóa mạnh mẽ, ngăn chặn hầu hết lỗi không khớp định dạng.

Giải tuần tự hóa trên iOS

JSONDecoder là cơ chế giải tuần tự hóa tiêu chuẩn trong iOS SDK, hoạt động với giao thức Codable. JSONDecoder tự động phân tích JSON thành các thể hiện struct hoặc class, hỗ trợ đối tượng lồng nhau, mảng và kiểu nguyên thủy. Cho logic tùy chỉnh, phương thức init(from: Decoder) được sử dụng — nó cho phép xử lý các định dạng không chuẩn, trường thiếu trong phiên bản API cũ hoặc kết hợp nhiều khóa JSON thành một thuộc tính.

swift
struct Order: Decodable {
    let orderId: String
    let amount: Double
    let status: OrderStatus

    enum OrderStatus: String, Decodable {
        case pending, confirmed, shipped, cancelled
    }
}

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let order = try decoder.decode(Order.self, from: jsonData)

DateDecodingStrategy xác định cách JSONDecoder diễn giải chuỗi ngày tháng. .iso8601 được sử dụng phổ biến nhất — định dạng REST API tiêu chuẩn. Enum OrderStatus lồng nhau tự động được giải mã từ giá trị chuỗi JSON. Điều này tránh các số ma thuật và làm cho mã tự ghi chú — trạng thái đơn hàng luôn có một tập giá trị được xác định nghiêm ngặt.

Property Wrappers trong Codable

Từ Swift 4.2, Codable hỗ trợ property wrappers cho giải tuần tự hóa tùy chỉnh các thuộc tính riêng lẻ. @DefaultValue là một wrapper phổ biến đặt giá trị mặc định nếu trường bị thiếu trong JSON. @LosslessString chuyển đổi chuỗi thành số và ngược lại. Điều này đặc biệt hữu ích khi máy chủ gửi id dưới dạng chuỗi "123" nhưng mô hình mong đợi Int. Property wrappers giảm mã mẫu trong init(from:) và làm cho mô hình sạch hơn.

Giải tuần tự hóa trên Android

Trên Android, việc chọn thư viện giải tuần tự hóa phụ thuộc vào ngôn ngữ và yêu cầu dự án. Gson của Google là lựa chọn phổ biến nhất, hoạt động qua reflection nhưng gặp vấn đề hiệu suất với các cấu trúc phân cấp phức tạp. Moshi của Square hỗ trợ cả reflection và code generation, tiêu thụ ít bộ nhớ hơn và xử lý phản hồi lớn nhanh hơn. kotlinx.serialization của JetBrains là giải pháp Kotlin gốc với tích hợp trình biên dịch và không sử dụng reflection.

kotlin
@Serializable
data class User(
    @SerialName("user_id")
    val userId: Int,
    val name: String,
    val email: String,
    @SerialName("created_at")
    val createdAt: String
)

val json = Json { ignoreUnknownKeys = true }
val user = json.decodeFromString<User>(response)

@Serializable là một chú thích trình biên dịch Kotlin kích hoạt tạo mã cho lớp. Tham số ignoreUnknownKeys ngăn lỗi nếu máy chủ gửi trường thiếu trong mô hình. Để ánh xạ khóa snake_case, @SerialName được sử dụng — tương đương với convertFromSnakeCase từ iOS. Theo JetBrains (2026), thư viện hỗ trợ đa nền tảng: cùng một lớp Serializable hoạt động trên Android, iOS (KMP) và Kotlin phía máy chủ.

So sánh Gson, Moshi và kotlinx.serialization

Sự lựa chọn giữa các thư viện là sự đánh đổi giữa tốc độ và linh hoạt. Gson phù hợp cho nguyên mẫu và dự án Java — không yêu cầu chú thích và hoạt động ngay. Moshi ở vị trí trung gian: codegen qua @JsonClass(generateAdapter = true) cho tốc độ gần với kotlinx.serialization, trong khi chế độ reflection cung cấp sự linh hoạt của Gson. kotlinx.serialization là lựa chọn nhanh nhất cho dự án Kotlin thuần túy nhưng yêu cầu Kotlin 1.4+ và plugin Kotlin Serialization trong Gradle.

Thư việnCơ chếTốc độKMP
GsonReflectionThấpKhông
MoshiReflection / CodegenTrung bình / CaoKhông
kotlinx.serializationCodegen trình biên dịchCao

Các lỗi phổ biến và cách phòng tránh

Type mismatch là tình huống JSON chứa giá trị của một kiểu nhưng mô hình lại mong đợi kiểu khác. Máy chủ đã gửi chuỗi "42" thay vì số, hoặc số 1 thay vì boolean true. Trên iOS, JSONDecoder sẽ ném DecodingError.typeMismatch theo mặc định; trên Android, Gson sẽ cố gắng chuyển đổi, trong khi Moshi và kotlinx.serialization yêu cầu bộ điều hợp rõ ràng. Giải pháp là sử dụng chiến lược lenient hoặc bộ giải tuần tự hóa tùy chỉnh cho các trường cụ thể.

Trường thiếu và Nullable

Khi máy chủ không bao gồm trường tùy chọn, mã sẽ bị lỗi. Trường Optional trong Swift và kiểu nullable trong Kotlin giải quyết vấn đề: nếu trường là null hoặc thiếu trong JSON, thuộc tính nhận nil/null và ứng dụng tiếp tục hoạt động. Cho các trường bắt buộc, nên kiểm tra sự tồn tại của chúng ở cấp độ máy khách API trước khi giải tuần tự hóa. Moshi và kotlinx.serialization yêu cầu tất cả các trường theo mặc định — đánh dấu nullable và giá trị mặc định loại bỏ hạn chế này.

Không tương thích phiên bản API

Thay đổi cấu trúc JSON trên máy chủ là nguồn lỗi phổ biến trong sản xuất. Thông lệ tiêu chuẩn là quản lý phiên bản lược đồ qua trường version trong đối tượng gốc và hỗ trợ 2-3 phiên bản trước trên máy khách. kotlinx.serialization cho phép khai báo nhiều mô hình cho các phiên bản khác nhau và chọn mô hình phù hợp dựa trên trường version sau khi phân tích ban đầu thành JsonElement. Bảo vệ bổ sung bao gồm ignoreUnknownKeys cho trường mới và giá trị mặc định cho trường có thể bị xóa.

LỗiTriệu chứngThư viện có bảo vệ
Type mismatchDecodingError / Ngoại lệkotlinx — coerceInputValues = true
Thiếu trườngLỗi khi truy cậpMoshi — @Transient + default
Định dạng ngày saiLỗi giải mãJSONDecoder — dateDecodingStrategy
Trường thừaBị bỏ qua hoặc lỗikotlinx — ignoreUnknownKeys = true
Null trong trường non-nullLỗi thời gian chạyMoshi — lenient với @Nullable

Ghi nhật ký lỗi giải tuần tự hóa là một thực hành bắt buộc trong sản xuất. Bọc decode trong do/catch, ghi nhật ký JSON thô và kiểu mô hình dự kiến vào Crashlytics hoặc Sentry. Điều này cho phép nhanh chóng xác định trường nào của API nào bị hỏng và trên phiên bản ứng dụng nào. Nếu không ghi nhật ký, lỗi giải tuần tự hóa trông giống như một lỗi bí ẩn không có ngữ cảnh.

Câu hỏi thường gặp

Giải tuần tự hóa khác với phân tích cú pháp (parsing) như thế nào?

Phân tích cú pháp là việc chia văn bản có cấu trúc thành các phần tử thành phần mà không nhất thiết phải tạo mô hình đã định kiểu. Giải tuần tự hóa là một trường hợp cụ thể của phân tích cú pháp với kết quả là một đối tượng ngôn ngữ hoàn chỉnh với các kiểu thuộc tính đã biết. Phân tích cú pháp có thể theo luồng, giải tuần tự hóa luôn tạo một đối tượng hoàn chỉnh.

Nên chọn thư viện giải tuần tự hóa nào cho dự án Android mới?

Cho dự án Kotlin thuần túy, khuyến nghị kotlinx.serialization — nó được tích hợp vào trình biên dịch, không sử dụng reflection và hỗ trợ Kotlin Multiplatform. Cho dự án Java hiện có — Moshi với code generation. Gson nên để lại cho các dự án kế thừa nơi việc thay thế nó sẽ đòi hỏi nỗ lực đáng kể.

Làm gì nếu máy chủ gửi snake_case nhưng mô hình sử dụng camelCase?

Trên iOS, sử dụng keyDecodingStrategy = .convertFromSnakeCase trong JSONDecoder. Trên Android với kotlinx.serialization, sử dụng @SerialName cho mỗi trường. Trong Moshi, áp dụng @Json(name="field_name") hoặc JsonAdapter.Factory toàn cục. Một phong cách nhất quán ở cấp dự án là thông lệ tốt nhất được thỏa thuận trong hợp đồng API.

Tại sao giải tuần tự hóa bị lỗi trong sản xuất nhưng không trong phát triển?

Nguyên nhân phổ biến nhất là null bất ngờ từ máy chủ trên một trường được khai báo là bắt buộc. Trong phát triển, máy chủ trả về dữ liệu đầy đủ; trong sản xuất, nó trả về phản hồi rút gọn. Giải pháp: đánh dấu tất cả các trường có thể thiếu là nullable (Kotlin) hoặc optional (Swift), sử dụng ignoreUnknownKeys và giá trị mặc định.

Cái nào nhanh hơn — Reflection hay Code generation trong giải tuần tự hóa?

Code generation (Moshi codegen, kotlinx.serialization, Codable) nhanh hơn 2-4 lần so với reflection trong các điểm chuẩn của Google. Ngoài tốc độ, tạo mã an toàn hơn về kiểu, không yêu cầu siêu dữ liệu lớp tại thời gian chạy và lỗi kiểu được phát hiện tại thời gian biên dịch, không phải trong quá trình giải tuần tự hóa.

Tổng kết

  • Giải tuần tự hóa là một quá trình cơ bản của phát triển di động khôi phục một đối tượng từ JSON, XML hoặc Protobuf để sử dụng trong mã ứng dụng.
  • iOS sử dụng JSONDecoder với giao thức Codable, cung cấp chuyển đổi tự động từ JSON sang mô hình với các chiến lược khóa và ngày tháng.
  • Android cung cấp ba công cụ: Gson (reflection), Moshi (reflection/codegen) và kotlinx.serialization (tạo bởi trình biên dịch qua @Serializable).
  • Các lỗi phổ biến — type mismatch, thiếu trường, null trong trường non-null và không tương thích phiên bản API — được ngăn chặn bằng kiểu nullable, ignoreUnknownKeys và quản lý phiên bản.
  • Code generation an toàn và nhanh hơn reflection, do đó được khuyến nghị cho các bản dựng sản xuất của ứng dụng di động.
  • Chiến lược ánh xạ — keyDecodingStrategy trên iOS và @SerialName trên Android giải quyết sự không khớp phong cách đặt tên giữa máy chủ và máy khách.
  • Hãy chắc chắn ghi nhật ký lỗi giải tuần tự hóa trong Crashlytics hoặc Sentry để chẩn đoán nhanh sự cố sản xuất.

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm