Moshi: khái niệm chính, thư viện JSON cho Kotlin và cách hoạt động

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

Moshi là một thư viện JSON hiện đại từ Square, được tạo ra dành riêng cho Kotlin và Android với những hạn chế của Gson. Nó hoàn toàn tương thích với tính an toàn null của Kotlin, tạo mã tại thời điểm biên dịch và không sử dụng phản xạ, giúp cải thiện hiệu suất và độ tin cậy. Theo Square Moshi, 2024, Moshi cung cấp khả năng tuần tự hóa có thể dự đoán và hỗ trợ các bộ chuyển đổi tùy chỉnh cho mọi loại dữ liệu.

Điểm chính

  • Moshi — thư viện JSON từ Square cho Kotlin và Android không cần phản xạ
  • Bộ chuyển đổi Kotlin — hỗ trợ tích hợp cho data class, giá trị mặc định và an toàn null
  • @Json — chú thích để cấu hình tên trường và bỏ qua thuộc tính
  • Bộ chuyển đổi — logic tuần tự hóa tùy chỉnh qua @ToJson và @FromJson
  • Tạo mã — Moshi tạo bộ chuyển đổi tại thời điểm biên dịch qua kapt hoặc KSP

Moshi là gì

Moshi là một thư viện JSON cho JVM, Android và Kotlin Multiplatform, được tạo bởi Square (tác giả của OkHttp và Retrofit). Không giống Gson, Moshi không dựa vào phản xạ — các bộ chuyển đổi được tạo tại thời điểm biên dịch qua chú thích @JsonClass(generateAdapter = true). Điều này làm cho Moshi nhanh hơn, an toàn hơn và dễ dự đoán hơn khi làm việc với các cấu trúc dành riêng của Kotlin.

Triết lý và lợi ích

Sự khác biệt chính giữa Moshi và các phiên bản trước là việc loại bỏ phản xạ. Phản xạ cho phép Gson làm việc với bất kỳ lớp nào mà không cần chuẩn bị, nhưng cái giá phải trả là khởi tạo chậm, không thể tối ưu hóa bởi trình biên dịch và nguy cơ lỗi trong thời gian chạy. Moshi yêu cầu khai báo lớp rõ ràng để tạo mã, nhưng đổi lại mang lại tốc độ của mã viết tay và an toàn kiểu hoàn toàn tại thời điểm biên dịch.

kotlin
// Thêm Moshi vào build.gradle
dependencies {
    implementation "com.squareup.moshi:moshi:1.15.0"
    implementation "com.squareup.moshi:moshi-kotlin:1.15.0"
    kapt "com.squareup.moshi:moshi-kotlin-codegen:1.15.0"
}

// Mô hình đơn giản với tạo mã
@JsonClass(generateAdapter = true)
data class User(
    @Json(name = "user_id")
    val id: Int,
    val name: String,
    val email: String,
    val avatar: String? = null
)

// Sử dụng
val moshi = Moshi.Builder()
    .build()
val jsonAdapter = moshi.adapter(User::class.java)

Cài đặt và cấu hình

Để bắt đầu làm việc với Moshi, bạn cần thêm các phụ thuộc vào build.gradle và chú thích các mô hình. Moshi.Builder đóng vai trò là điểm vào: qua nó, các bộ chuyển đổi tích hợp cho các loại chuẩn, bộ chuyển đổi tùy chỉnh được thêm vào và hành vi của thư viện được cấu hình. Moshi hỗ trợ các bộ chuyển đổi cho Date, Enum, Collection và Map ngay khi cài đặt, nhưng các lớp Kotlin yêu cầu module moshi-kotlin. Không giống Gson, Moshi không sử dụng phản xạ cho các lớp Kotlin theo mặc định — để làm điều này, KotlinJsonAdapterFactory được kết nối, đóng vai trò dự phòng khi không sử dụng tạo mã hoặc lớp không được chú thích bằng @JsonClass. Cách tiếp cận này đảm bảo nhà phát triển chọn rõ ràng giữa hiệu suất của tạo mã và tính linh hoạt của phản xạ cho từng lớp cụ thể.

Tạo Moshi và thêm bộ chuyển đổi

Sau khi xây dựng Moshi qua Builder, nhà phát triển nhận được một phiên bản Moshi và yêu cầu một bộ chuyển đổi cho lớp mong muốn. JsonAdapter là đối tượng trung tâm thực hiện tuần tự hóa qua toJson() và giải tuần tự hóa qua fromJson(). Moshi tự động sử dụng bộ chuyển đổi được tạo nếu lớp được chú thích bằng @JsonClass(generateAdapter = true), nếu không thì áp dụng KotlinJsonAdapterFactory phản xạ như một giải pháp dự phòng. Cách tiếp cận này kết hợp tốc độ của tạo mã với tính linh hoạt của cơ chế phản xạ cho các dự án ở mọi quy mô và độ phức tạp. Moshi phù hợp cho cả ứng dụng nhỏ và các dự án doanh nghiệp lớn với hàng trăm mô hình dữ liệu.

kotlin
// Cấu hình Moshi với KotlinJsonAdapterFactory
val moshi = Moshi.Builder()
    .add(KotlinJsonAdapterFactory())
    .add(LocalDateAdapter())
    .build()

// Sử dụng bộ chuyển đổi
val adapter = moshi.adapter(User::class.java)

// Tuần tự hóa
val user = User(1, "Alice", "alice@test.com")
val json = adapter.toJson(user)

// Giải tuần tự hóa
val jsonString = """{"user_id":2,"name":"Bob","email":"bob@test.com"}"""
val parsedUser = adapter.fromJson(jsonString)

// Làm việc với danh sách
val listAdapter = moshi.adapter(
    Types.newParameterizedType(
        List::class.java,
        User::class.java
    )
)

Chú thích và bộ chuyển đổi

Moshi sử dụng chú thích để cấu hình tuần tự hóa và hỗ trợ các loại tùy chỉnh. @Json(name = "...") đặt khóa JSON cho một trường. @Transient loại trừ một trường khỏi tuần tự hóa. @JsonClass(generateAdapter = true) kích hoạt tạo mã. Đối với logic tùy chỉnh, Moshi cung cấp các chú thích @ToJson và @FromJson, có thể được đặt trong một lớp bộ chuyển đổi riêng.

@Json và bộ chuyển đổi tùy chỉnh

Chú thích @Json thay thế @SerializedName của Gson và hoạt động tương tự: trường kotlinName được liên kết với khóa JSON "kotlin_name". Đối với các loại mà Moshi không thể tuần tự hóa theo mặc định (ví dụ LocalDate), nhà phát triển tạo một lớp với các phương thức @ToJson và @FromJson. Các bộ chuyển đổi được đăng ký qua Moshi.Builder.add() và áp dụng toàn cục hoặc cho một loại cụ thể. Moshi hỗ trợ các lớp sealed và tuần tự hóa đa hình qua @JsonClass với bộ phân biệt rõ ràng, cho phép làm việc với hệ phân cấp loại trong JSON mà không cần kiểm tra trường thủ công. Trong quá trình giải tuần tự hóa, Moshi mặc định bỏ qua các khóa JSON không xác định, đảm bảo tương thích ngược khi thêm trường mới phía máy chủ mà không thay đổi mã máy khách. Để gỡ lỗi, chế độ nghiêm ngặt có thể được bật qua failOnUnknown, ném ra ngoại lệ khi phát hiện các khóa không xác định.

kotlin
// Bộ chuyển đổi tùy chỉnh cho LocalDate
class LocalDateAdapter {

    @ToJson
    fun toJson(date: LocalDate): String {
        return date.format(DateTimeFormatter.ISO_LOCAL_DATE)
    }

    @FromJson
    fun fromJson(dateString: String): LocalDate {
        return LocalDate.parse(dateString)
    }
}

// Mô hình với chú thích Moshi
@JsonClass(generateAdapter = true)
data class Event(
    @Json(name = "event_id")
    val id: Int,

    @Json(name = "event_date")
    val date: LocalDate,

    @Transient
    val localCache: String? = null
)

// Đăng ký bộ chuyển đổi
val moshi = Moshi.Builder()
    .add(LocalDateAdapter())
    .add(KotlinJsonAdapterFactory())
    .build()

Moshi vs Gson

So sánh Moshi và Gson là một câu hỏi phổ biến khi chọn thư viện JSON cho dự án Android. Moshi chiến thắng trong phát triển Kotlin hiện đại nhờ tạo mã, an toàn null và tốc độ. Gson vẫn phù hợp cho các dự án Java, mã cũ và các kịch bản mà cấu hình tối thiểu là quan trọng. Sự khác biệt trở nên rõ rệt với khối lượng dữ liệu lớn và các mô hình phức tạp.

Hiệu suất và an toàn

Các bài kiểm tra hiệu suất cho thấy Moshi với tạo mã nhanh hơn 2–5 lần so với Gson trong các thao tác tuần tự hóa và giải tuần tự hóa. Lợi thế chính của Moshi là xử lý chính xác tính an toàn null của Kotlin: nếu một trường bị thiếu trong JSON và mô hình khai báo nó là non-null không có giá trị mặc định, Moshi ném ngoại lệ tại thời điểm giải tuần tự hóa, ngăn chặn các lỗi ẩn.

Đặc điểmGsonMoshi
Cơ chếphản xạtạo mã / phản xạ
An toàn nullkhông xem xéthỗ trợ đầy đủ Kotlin
Tốc độtrung bìnhcao
Giá trị mặc địnhkhông hỗ trợhỗ trợ
Kotlin Multiplatformkhông
Kích thước thư viện~240 Kb~150 Kb

Lựa chọn giữa Moshi và Gson phụ thuộc vào bối cảnh dự án. Các dự án mới trên Kotlin được hưởng lợi từ Moshi nhờ an toàn kiểu và hiệu suất. Gson vẫn là lựa chọn hợp lý để hỗ trợ mã Java, cấu trúc JSON động hoặc khi sự đơn giản trong cấu hình quan trọng hơn tốc độ. Đối với Kotlin Multiplatform, Moshi là lựa chọn duy nhất trong hai lựa chọn hỗ trợ nền tảng này.

Khi di chuyển từ Gson sang Moshi, các thay đổi chính liên quan đến chú thích và bộ chuyển đổi. @SerializedName của Gson được thay thế bằng @Json(name = "..."), và JsonSerializer/JsonDeserializer tùy chỉnh bằng cặp @ToJson/@FromJson. Đối với các mô hình có giá trị mặc định và trường nullable, Moshi hoạt động dễ dự đoán hơn: nếu một trường non-null không có giá trị mặc định bị thiếu trong JSON, Moshi ném JsonDataException, ngăn chặn NPE ẩn. Tích hợp với Retrofit qua MoshiConverterFactory được thêm bằng một phụ thuộc duy nhất và không yêu cầu thay đổi kiến trúc lớp mạng. Để làm xáo trộn qua ProGuard hoặc R8, cần thêm các quy tắc để bảo toàn các lớp được chú thích @JsonClass và các bộ chuyển đổi được tạo, nếu không việc tuần tự hóa sẽ bị hỏng trong bản dựng release. Nhìn chung, việc di chuyển từ Gson sang Moshi là hợp lý trong các dự án Kotlin mới nơi hiệu suất và an toàn kiểu là quan trọng.

kotlin
// So sánh tuần tự hóa: Gson vs Moshi
data class Sample(
    val name: String,
    val count: Int,
    val tags: List<String> = listOf()
)

// Gson: hoạt động qua phản xạ
val gson = Gson()
val fromGson = gson.fromJson("""{"name":"test"}""",
    Sample::class.java)
// count = 0 (mặc định), nhưng an toàn null không được kiểm tra

// Moshi: yêu cầu bộ chuyển đổi, an toàn null rõ ràng
@JsonClass(generateAdapter = true)
data class SampleMoshi(
    val name: String,
    val count: Int,
    val tags: List<String> = listOf()
)

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

Moshi trong Android là gì?

Moshi là thư viện JSON của Square cho Kotlin và Android sử dụng tạo mã thay vì phản xạ. Nó cung cấp hiệu suất cao, xử lý chính xác tính an toàn null của Kotlin và tương thích với Kotlin Multiplatform.

Moshi tốt hơn Gson như thế nào?

Moshi vượt trội hơn Gson về tốc độ (nhanh hơn 2–5 lần nhờ tạo mã), an toàn (tôn trọng chú thích null của Kotlin) và kích thước (nhỏ hơn ~90 Kb). Moshi cũng hỗ trợ Kotlin Multiplatform và giá trị mặc định trong data class.

Chú thích @JsonClass trong Moshi hoạt động như thế nào?

@JsonClass(generateAdapter = true) hướng dẫn Moshi tạo một bộ chuyển đổi cho lớp đã cho tại thời điểm biên dịch. Bộ chuyển đổi được tạo thực hiện tuần tự hóa trực tiếp, không cần phản xạ, mang lại hiệu suất tối đa.

Làm thế nào để tạo bộ chuyển đổi Moshi tùy chỉnh?

Tạo một lớp với các phương thức được chú thích bằng @ToJson (tuần tự hóa) và @FromJson (giải tuần tự hóa). Đăng ký phiên bản qua Moshi.Builder.add(). Moshi sẽ tự động tìm và áp dụng bộ chuyển đổi khi làm việc với loại tương ứng.

Moshi có hỗ trợ Kotlin Multiplatform không?

Có, Moshi hỗ trợ Kotlin Multiplatform từ phiên bản 1.13.0. Điều này làm cho nó trở thành giải pháp JSON phổ biến duy nhất cho các dự án KMP, cho phép sử dụng mã tuần tự hóa chung trên tất cả các nền tảng mục tiêu.

Tổng kết

  • Moshi — thư viện JSON hiện đại của Square với tạo mã thay vì phản xạ
  • @JsonClass — chú thích tạo bộ chuyển đổi, mang lại tốc độ của mã viết tay
  • @Json — cấu hình khóa JSON, @Transient — loại trừ trường khỏi tuần tự hóa
  • @ToJson và @FromJson — API đơn giản cho bộ chuyển đổi tùy chỉnh của mọi loại
  • An toàn null — Moshi tôn trọng chú thích Kotlin và ném ngoại lệ khi không khớp
  • Hiệu suất — nhanh hơn 2–5 lần so với Gson trong các thao tác tuần tự hóa và giải tuần tự hóa
  • Kotlin Multiplatform — hỗ trợ KMP cho mã tuần tự hóa phổ quá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