Работа с JSON в Kotlin: парсинг и сериализация данных

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Работа с JSON в Kotlin: полное руководство по парсингу и сериализации

JSON (JavaScript Object Notation) остается одним из самых популярных форматов обмена данными в современной веб-разработке. При работе с Kotlin, будь то серверная часть на Ktor или мобильное приложение под Android, умение эффективно парсить и сериализовать JSON — обязательный навык. В этой статье мы разберем три основных подхода к работе с JSON в Kotlin: использование библиотек Gson, Moshi и официального решения от JetBrains — kotlinx.serialization.

Почему Kotlin требует особого подхода к JSON?

Kotlin — статически типизированный язык с такими особенностями, как null-безопасность, data-классы и свойства по умолчанию. Библиотеки для работы с JSON должны учитывать эти особенности, чтобы код был не только рабочим, но и идиоматичным. Неправильная настройка может привести к NullPointerException или неожиданному поведению при десериализации.

1. Использование Gson для работы с JSON

Gson от Google — одна из самых старых и распространенных библиотек. Она проста в использовании, но имеет некоторые особенности при работе с Kotlin.

Подключение зависимости

// build.gradle.kts
implementation("com.google.code.gson:gson:2.10.1")

Сериализация объекта в JSON

import com.google.gson.Gson

data class User(
    val id: Int,
    val name: String,
    val email: String? = null
)

fun main() {
    val user = User(1, "Иван Петров", "ivan@example.com")
    val gson = Gson()
    val json = gson.toJson(user)
    println(json)
    // Вывод: {"id":1,"name":"Иван Петров","email":"ivan@example.com"}
}

Парсинг JSON в объект

fun parseUser(jsonString: String): User {
    val gson = Gson()
    return gson.fromJson(jsonString, User::class.java)
}

fun main() {
    val json = """{"id":2,"name":"Анна Смирнова","email":null}"""
    val user = parseUser(json)
    println(user.name) // Анна Смирнова
}

Важно: Gson использует рефлексию Java и может не учитывать null-безопасность Kotlin. При десериализации поля, объявленные как non-null, могут получить значение null, что приведет к ошибке во время выполнения. Рекомендуется использовать @JvmOverloads и конструкторы со значениями по умолчанию.

2. Moshi — современная альтернатива от Square

Moshi создавался с учетом особенностей Kotlin и предлагает лучшую интеграцию с null-безопасностью и data-классами.

Подключение зависимости

// build.gradle.kts
implementation("com.squareup.moshi:moshi-kotlin:1.15.0")
kapt("com.squareup.moshi:moshi-kotlin-codegen:1.15.0")

Пример работы с Moshi

import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory

data class Product(
    val id: Int,
    val title: String,
    val price: Double,
    val inStock: Boolean = false
)

fun main() {
    val moshi = Moshi.Builder()
        .addLast(KotlinJsonAdapterFactory())
        .build()

    val adapter = moshi.adapter(Product::class.java)

    // Сериализация
    val product = Product(101, "Ноутбук", 89999.99, true)
    val json = adapter.toJson(product)
    println(json)
    // {"id":101,"title":"Ноутбук","price":89999.99,"inStock":true}

    // Десериализация
    val jsonString = """{"id":102,"title":"Мышь","price":2500.00}"""
    val parsedProduct = adapter.fromJson(jsonString)
    println(parsedProduct?.title) // Мышь
    println(parsedProduct?.inStock) // false (значение по умолчанию)
}

Moshi автоматически обрабатывает значения по умолчанию в data-классах и корректно работает с nullable-типами. Для лучшей производительности рекомендуется использовать кодогенерацию через аннотацию @JsonClass.

3. kotlinx.serialization — официальное решение от JetBrains

Это наиболее "родной" способ работы с JSON в Kotlin. Библиотека использует компиляторные плагины и не полагается на рефлексию, что делает ее быстрой и безопасной.

Подключение зависимости

// build.gradle.kts
plugins {
    kotlin("plugin.serialization") version "1.9.0"
}

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
}

Пример с аннотацией @Serializable

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.encodeToString
import kotlinx.serialization.decodeFromString

@Serializable
data class Book(
    val isbn: String,
    val title: String,
    val author: String,
    val year: Int? = null
)

fun main() {
    val json = Json { 
        prettyPrint = true
        ignoreUnknownKeys = true // игнорировать неизвестные поля
    }

    // Сериализация
    val book = Book("978-5-17-123456-7", "Kotlin в действии", "Дмитрий Жемеров", 2023)
    val jsonString = json.encodeToString(book)
    println(jsonString)

    // Десериализация
    val input = """{"isbn":"978-5-17-987654-3","title":"Программирование на Kotlin","author":"Андрей Бреслав"}"""
    val parsedBook = json.decodeFromString<Book>(input)
    println(parsedBook.title) // Программирование на Kotlin
    println(parsedBook.year) // null
}

Работа с вложенными объектами и списками

@Serializable
data class Author(val name: String, val age: Int)

@Serializable
data class Library(
    val name: String,
    val books: List<Book>,
    val authors: Map<String, Author>
)

fun main() {
    val library = Library(
        name = "Центральная библиотека",
        books = listOf(
            Book("1", "Kotlin Basics", "John Doe"),
            Book("2", "Advanced Kotlin", "Jane Smith")
        ),
        authors = mapOf(
            "john" to Author("John Doe", 35),
            "jane" to Author("Jane Smith", 28)
        )
    )

    val json = Json { prettyPrint = true }
    println(json.encodeToString(library))
}

Сравнение библиотек и рекомендации

<

Блоги

Рекомендаций по книгам

Библиотека