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

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

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

Начать курс

Введение: почему JSON — основа современного Kotlin-разработчика

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

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

Прежде чем писать код, необходимо добавить библиотеки в файл build.gradle.kts (для Gradle). Рассмотрим оба варианта.

Вариант 1: kotlinx.serialization (рекомендуемый)

  • Добавьте плагин в plugins: kotlin("plugin.serialization") version "1.9.22"
  • В dependencies укажите: implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")

Вариант 2: Gson (для совместимости с Java-проектами)

  • В dependencies добавьте: implementation("com.google.code.gson:gson:2.10.1")
// build.gradle.kts — полный пример для kotlinx.serialization
plugins {
    kotlin("jvm") version "1.9.22"
    kotlin("plugin.serialization") version "1.9.22"
}

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

Парсинг JSON в Kotlin: от простого к сложному

Парсинг (десериализация) — это преобразование JSON-строки в объект Kotlin. Рассмотрим на примере данных о пользователе.

Пример данных

{
  "id": 123,
  "name": "Анна",
  "email": "anna@example.com",
  "active": true
}

Создание Data Class

Для обоих библиотек используется один и тот же класс. Важно: для kotlinx.serialization нужно добавить аннотацию @Serializable.

import kotlinx.serialization.Serializable

@Serializable
data class User(
    val id: Int,
    val name: String,
    val email: String,
    val active: Boolean
)

Парсинг с помощью kotlinx.serialization

import kotlinx.serialization.json.Json

fun parseWithKotlinx(jsonString: String): User {
    val json = Json { ignoreUnknownKeys = true } // игнорируем неизвестные поля
    return json.decodeFromString<User>(jsonString)
}

// Использование:
fun main() {
    val json = """{"id":123,"name":"Анна","email":"anna@example.com","active":true}"""
    val user = parseWithKotlinx(json)
    println(user.name) // Анна
}

Парсинг с помощью Gson

import com.google.gson.Gson

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

// Использование:
fun main() {
    val json = """{"id":123,"name":"Анна","email":"anna@example.com","active":true}"""
    val user = parseWithGson(json)
    println(user.email) // anna@example.com
}

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

Обратный процесс — создание JSON-строки из объекта — не менее важен для отправки данных на сервер.

Сериализация с kotlinx.serialization

import kotlinx.serialization.encodeToString

fun serializeWithKotlinx(user: User): String {
    val json = Json { prettyPrint = true }
    return json.encodeToString(user)
}

// Результат:
// {
//   "id": 123,
//   "name": "Анна",
//   "email": "anna@example.com",
//   "active": true
// }

Сериализация с Gson

fun serializeWithGson(user: User): String {
    val gson = GsonBuilder().setPrettyPrinting().create()
    return gson.toJson(user)
}

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

В реальных проектах JSON редко бывает плоским. Научимся работать со списками и вложенными объектами.

Пример: список пользователей с адресами

{
  "users": [
    {
      "id": 1,
      "name": "Иван",
      "address": {
        "city": "Москва",
        "street": "Тверская"
      }
    },
    {
      "id": 2,
      "name": "Мария",
      "address": {
        "city": "Санкт-Петербург",
        "street": "Невский"
      }
    }
  ]
}

Data Class для сложной структуры

@Serializable
data class Address(val city: String, val street: String)

@Serializable
data class UserWithAddress(
    val id: Int,
    val name: String,
    val address: Address
)

@Serializable
data class UserList(val users: List<UserWithAddress>)

Парсинг списка

fun parseUserList(jsonString: String): UserList {
    val json = Json { ignoreUnknownKeys = true }
    return json.decodeFromString<UserList>(jsonString)
}

fun main() {
    val json = """
    {
      "users": [
        {"id": 1, "name": "Иван", "address": {"city": "Москва", "street": "Тверская"}},
        {"id": 2, "name": "Мария", "address": {"city": "Санкт-Петербург", "street": "Невский"}}
      ]
    }
    """.trimIndent()
    
    val result = parseUserList(json)
    result.users.forEach { println("${it.name} живет в ${it.address.city}") }
}

Обработка ошибок и null-значений

JSON из внешних источников часто содержит неожиданные данные. Рассмотрим, как сделать код устойчивым.

Null-поля и значения по умолчанию

Если поле может отсутствовать, используйте nullable-тип (String?) или значение по умолчанию.

@Serializable
data class Product(
    val id: Int,
    val name:                

Блоги

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