Moshi: ключові поняття, JSON-бібліотека Kotlin і як працює

Автор: IT Sectr Опубліковано: 2026-03-15 Час читання: 8 хв

Moshi — сучасна JSON-бібліотека від Square, створена спеціально для Kotlin і Android з урахуванням обмежень Gson. Вона повністю сумісна з null-безпекою Kotlin, генерує код на етапі компіляції і не використовує рефлексію, що підвищує продуктивність і надійність. За даними Square Moshi, 2024, Moshi забезпечує передбачувану серіалізацію і підтримує кастомні адаптери для будь-яких типів даних.

Головне

  • Moshi — JSON-бібліотека від Square для Kotlin і Android без рефлексії
  • Kotlin-адаптер — вбудована підтримка data class, default values і null safety
  • @Json — анотація для налаштування імені поля та ігнорування властивостей
  • Адаптери — кастомна логіка серіалізації через @ToJson і @FromJson
  • Кодогенерація — Moshi генерує адаптери на етапі компіляції через kapt або KSP

Що таке Moshi

Moshi — це JSON-бібліотека для JVM, Android і Kotlin Multiplatform, створена Square (авторами OkHttp і Retrofit). На відміну від Gson, Moshi не покладається на рефлексію — адаптери генеруються на етапі компіляції через анотацію @JsonClass(generateAdapter = true). Це робить Moshi швидшою, безпечнішою та передбачуванішою в роботі з Kotlin-специфічними конструкціями.

Філософія та переваги

Основна відмінність Moshi від попередників — відмова від рефлексії. Рефлексія дозволяє Gson працювати з будь-яким класом без підготовки, але платою є повільна ініціалізація, неможливість оптимізації компілятором і ризик помилок під час виконання. Moshi вимагає явного зазначення класів для кодогенерації, але натомість дає швидкість рукописного коду та повну типобезпеку на етапі компіляції.

kotlin
// Підключення Moshi в 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"
}

// Проста модель з кодогенерацією
@JsonClass(generateAdapter = true)
data class User(
    @Json(name = "user_id")
    val id: Int,
    val name: String,
    val email: String,
    val avatar: String? = null
)

// Використання
val moshi = Moshi.Builder()
    .build()
val jsonAdapter = moshi.adapter(User::class.java)

Підключення та налаштування

Для початку роботи з Moshi потрібно додати залежності в build.gradle та анотувати моделі. Moshi.Builder слугує точкою входу: через нього додаються вбудовані адаптери для стандартних типів, кастомні адаптери та налаштовується поведінка бібліотеки. Moshi підтримує адаптери для Date, Enum, Collection і Map з коробки, але для Kotlin-класів потрібен модуль moshi-kotlin. На відміну від Gson, Moshi не використовує рефлексію для Kotlin-класів за замовчуванням — для цього підключається KotlinJsonAdapterFactory, який слугує запасним варіантом, коли кодогенерація не застосовується або клас не анотований @JsonClass. Такий підхід гарантує, що розробник явно обирає між продуктивністю кодогенерації та гнучкістю рефлексії для кожного конкретного класу.

Створення Moshi та додавання адаптерів

Після збірки Moshi через Builder розробник отримує екземпляр Moshi та запитує адаптер для потрібного класу. JsonAdapter — центральний об'єкт, який виконує серіалізацію через toJson() та десеріалізацію через fromJson(). Moshi автоматично використовує згенерований адаптер, якщо клас анотований @JsonClass(generateAdapter = true), інакше застосовує рефлексивний KotlinJsonAdapterFactory як запасний варіант. Такий підхід поєднує швидкість кодогенерації з гнучкістю рефлексивного механізму для проектів будь-якого масштабу та рівня складності. Moshi чудово підходить як для невеликих додатків, так і для великих корпоративних проектів із сотнями моделей даних.

kotlin
// Налаштування Moshi з KotlinJsonAdapterFactory
val moshi = Moshi.Builder()
    .add(KotlinJsonAdapterFactory())
    .add(LocalDateAdapter())
    .build()

// Використання адаптера
val adapter = moshi.adapter(User::class.java)

// Серіалізація
val user = User(1, "Alice", "alice@test.com")
val json = adapter.toJson(user)

// Десеріалізація
val jsonString = """{"user_id":2,"name":"Bob","email":"bob@test.com"}"""
val parsedUser = adapter.fromJson(jsonString)

// Робота зі списком
val listAdapter = moshi.adapter(
    Types.newParameterizedType(
        List::class.java,
        User::class.java
    )
)

Анотації та адаптери

Moshi використовує анотації для налаштування серіалізації та підтримки кастомних типів. @Json(name = "...") задає JSON-ключ для поля. @Transient виключає поле з серіалізації. @JsonClass(generateAdapter = true) вмикає кодогенерацію. Для кастомної логіки Moshi надає анотації @ToJson і @FromJson, які можна розмістити в окремому класі-адаптері.

@Json і кастомні адаптери

Анотація @Json замінює Gson-івський @SerializedName і працює аналогічно: поле kotlinName пов'язується з JSON-ключем "kotlin_name". Для типів, які Moshi не вміє серіалізувати за замовчуванням (наприклад, LocalDate), розробник створює клас з методами @ToJson і @FromJson. Адаптери реєструються через Moshi.Builder.add() і застосовуються глобально або до конкретного типу. Moshi підтримує sealed class і поліморфну серіалізацію через @JsonClass з явним зазначенням дискримінатора, що дозволяє працювати з ієрархіями типів у JSON, не вдаючись до ручної перевірки полів. При десеріалізації Moshi за замовчуванням ігнорує невідомі ключі в JSON, що забезпечує зворотну сумісність при додаванні нових полів на стороні сервера без зміни клієнтського коду. Для налагодження можна увімкнути строгий режим через failOnUnknown, який викидає виняток при виявленні невідомих ключів.

kotlin
// Кастомний адаптер для 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)
    }
}

// Модель з анотаціями 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
)

// Реєстрація адаптера
val moshi = Moshi.Builder()
    .add(LocalDateAdapter())
    .add(KotlinJsonAdapterFactory())
    .build()

Moshi vs Gson

Порівняння Moshi і Gson — часте питання при виборі JSON-бібліотеки для Android-проекту. Moshi виграє в сучасній Kotlin-розробці завдяки кодогенерації, null-безпеці та швидкості. Gson залишається актуальним для Java-проектів, legacy-коду та сценаріїв, де важлива мінімальна конфігурація. Різниця стає помітною на великих обсягах даних і складних моделях.

Продуктивність і безпека

Тести продуктивності показують, що Moshi з кодогенерацією працює в 2–5 разів швидше Gson на операціях серіалізації та десеріалізації. Ключова перевага Moshi — коректна обробка null-безпеки Kotlin: якщо в JSON поле відсутнє, а в моделі воно оголошено як non-null без значення за замовчуванням, Moshi викидає виняток на етапі десеріалізації, запобігаючи прихованим помилкам.

ХарактеристикаGsonMoshi
Механізмрефлексіякодогенерація / рефлексія
Null safetyне враховуєповна підтримка Kotlin
Швидкістьсереднявисока
Default valuesне підтримуєпідтримує
Kotlin Multiplatformнітак
Розмір бібліотеки~240 Kb~150 Kb

Вибір між Moshi і Gson залежить від контексту проекту. Нові проекти на Kotlin виграють від Moshi завдяки типобезпеці та продуктивності. Gson залишається розумним вибором для підтримки Java-коду, динамічних структур JSON або коли простота підключення важливіша за швидкість. Для Kotlin Multiplatform Moshi є єдиним із двох варіантів, що підтримує цю платформу.

При міграції з Gson на Moshi основні зміни стосуються анотацій та адаптерів. Gson-івський @SerializedName замінюється на @Json(name = "..."), а кастомні JsonSerializer/JsonDeserializer — на пару @ToJson/@FromJson. Для моделей з default values і nullable-полями Moshi веде себе більш передбачувано: якщо в JSON відсутнє non-null поле без значення за замовчуванням, Moshi викидає JsonDataException, запобігаючи прихованим NPE. Інтеграція з Retrofit через MoshiConverterFactory додається однією залежністю і не вимагає зміни архітектури мережевого шару. Для обфускації через ProGuard або R8 необхідно додати правила збереження @JsonClass-анотованих класів і згенерованих адаптерів, інакше серіалізація зламається в релізній збірці. Загалом міграція з Gson на Moshi виправдана в нових Kotlin-проектах, де важливі продуктивність і типобезпека.

kotlin
// Порівняння серіалізації: Gson vs Moshi
data class Sample(
    val name: String,
    val count: Int,
    val tags: List<String> = listOf()
)

// Gson: працює через рефлексію
val gson = Gson()
val fromGson = gson.fromJson("""{"name":"test"}""",
    Sample::class.java)
// count = 0 (default), але null-небезпека не перевіряється

// Moshi: вимагає адаптера, null-безпека явна
@JsonClass(generateAdapter = true)
data class SampleMoshi(
    val name: String,
    val count: Int,
    val tags: List<String> = listOf()
)

Часто задавані питання

Що таке Moshi в Android?

Moshi — це JSON-бібліотека від Square для Kotlin і Android, яка використовує кодогенерацію замість рефлексії. Вона забезпечує високу продуктивність, коректну обробку null-безпеки Kotlin і сумісність з Kotlin Multiplatform.

Чим Moshi кращий за Gson?

Moshi перевершує Gson за швидкістю (в 2–5 разів швидше завдяки кодогенерації), безпеці (враховує null-анотації Kotlin) та розміром (менше на ~90 Кб). Moshi також підтримує Kotlin Multiplatform і default values в data class.

Як працює анотація @JsonClass в Moshi?

@JsonClass(generateAdapter = true) вказує Moshi згенерувати адаптер для даного класу на етапі компіляції. Згенерований адаптер виконує серіалізацію безпосередньо, без рефлексії, що дає максимальну продуктивність.

Як створити кастомний адаптер Moshi?

Створіть клас з методами, анотованими @ToJson (серіалізація) і @FromJson (десеріалізація). Зареєструйте екземпляр через Moshi.Builder.add(). Moshi автоматично знайде і застосує адаптер при роботі з відповідним типом.

Чи підтримує Moshi Kotlin Multiplatform?

Так, Moshi підтримує Kotlin Multiplatform починаючи з версії 1.13.0. Це робить його єдиним популярним JSON-рішенням для KMP-проектів, дозволяючи використовувати спільний код серіалізації на всіх цільових платформах.

Підсумки

  • Moshi — сучасна JSON-бібліотека від Square з кодогенерацією замість рефлексії
  • @JsonClass — анотація для генерації адаптера, що забезпечує швидкість рукописного коду
  • @Json — налаштування JSON-ключів, @Transient — виключення полів із серіалізації
  • @ToJson і @FromJson — простий API для кастомних адаптерів будь-яких типів
  • Null safety — Moshi враховує Kotlin-анотації та викидає виняток при невідповідності
  • Продуктивність — в 2–5 разів швидше Gson на операціях серіалізації та десеріалізації
  • Kotlin Multiplatform — підтримка KMP для універсального коду серіалізації

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також