Как парсить JSON в Kotlin: лучшие библиотеки и примеры кода
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
Я пытался использовать встроенный JSONObject из Android SDK, но код получается ужасным:
val jsonString = """{"userId":1,"id":1,"title":"delectus aut autem","completed":false}"""
val jsonObject = JSONObject(jsonString)
val userId = jsonObject.getInt("userId")
val id = jsonObject.getInt("id")
val title = jsonObject.getString("title")
val completed = jsonObject.getBoolean("completed")
Это же просто ад! Для каждого поля нужно писать отдельный вызов, легко ошибиться в названии поля, да и типы нужно указывать вручную. А если JSON вложенный или содержит массивы — вообще кошмар.
Подскажите, пожалуйста, как правильно парсить JSON в Kotlin? Какие библиотеки сейчас актуальны? Хочется, чтобы код был лаконичным, типобезопасным и с минимумом шаблонного кода. Может, есть что-то вроде data class с аннотациями? Буду благодарен за примеры!
<<Лучший способ: Kotlinx Serialization
Самое современное и идиоматичное решение для Kotlin — это kotlinx.serialization. Эта библиотека разрабатывается JetBrains специально для Kotlin, поддерживает мультиплатформенность и не требует рефлексии, что даёт отличную производительность.
Шаг 1: Подключение библиотеки
Добавьте в build.gradle.kts (или build.gradle):
// В секции plugins
plugins {
kotlin("plugin.serialization") version "1.9.22"
}
// В секции dependencies
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
}
Шаг 2: Определите data class
Создайте класс, соответствующий структуре JSON, и добавьте аннотацию @Serializable:
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
@Serializable
data class Todo(
val userId: Int,
val id: Int,
val title: String,
val completed: Boolean
)
Шаг 3: Парсинг одной строки
fun main() {
val jsonString = """{"userId":1,"id":1,"title":"delectus aut autem","completed":false}"""
val todo = Json.decodeFromString<Todo>(jsonString)
println(todo.title) // delectus aut autem
println(todo.completed) // false
}
Работа с массивами и вложенными объектами
Допустим, у вас есть такой JSON:
[
{"userId":1, "id":1, "title":"Task 1", "completed":false},
{"userId":1, "id":2, "title":"Task 2", "completed":true}
]
Парсинг массива:
val jsonArray = """[{"userId":1,...}, {"userId":2,...}]"""
val todos: List<Todo> = Json.decodeFromString<List<Todo>>(jsonArray)
Настройка парсера
Вы можете настроить поведение парсера через объект Json:
val json = Json {
prettyPrint = true
ignoreUnknownKeys = true // игнорировать лишние поля
isLenient = true // допускать неточности в формате
coerceInputValues = true // приводить типы автоматически
}
// Использование:
val todo = json.decodeFromString<Todo>(jsonString)
Сериализация (обратный процесс)
Чтобы превратить объект обратно в JSON:
val todo = Todo(1, 1, "My task", false)
val jsonString = Json.encodeToString(todo)
println(jsonString) // {"userId":1,"id":1,"title":"My task","completed":false}
Почему это лучший выбор?
- Типобезопасность — компилятор проверяет типы полей
- Минимум кода — одна аннотация и один вызов функции
- Производительность — без рефлексии, код генерируется на этапе компиляции
- Мультиплатформенность — работает на JVM, JS, Native
- Поддержка Kotlin — использует возможности языка: data class, sealed class, null safety
Альтернативы (если проект уже использует другую библиотеку)
Gson — если вы мигрируете с Java:
implementation("com.google.code.gson:gson:2.10.1")
// Использование:
val gson = Gson()
val todo = gson.fromJson(jsonString, Todo::class.java)
Jackson — мощный, но более тяжёлый:
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.16.1")
// Использование:
val mapper = jacksonObjectMapper()
val todo = mapper.readValue<Todo>(jsonString)
Но для чистого Kotlin-проекта я настоятельно рекомендую kotlinx.serialization — это современный стандарт.
<<Альтернативный подход: ручной парсинг с JSONObject
Если вы не хотите подключать внешние библиотеки (например, в небольшом проекте или Android-приложении с минимальными зависимостями), можно использовать встроенный org.json.JSONObject из Android SDK или Java. Но код нужно писать аккуратнее.
Вот пример с использованием экстеншн-функций для удобства:
import org.json.JSONObject
fun JSONObject.toTodo(): Todo {
return Todo(
userId = getInt("userId"),
id = getInt("id"),
title = getString("title"),
completed = getBoolean("completed")
)
}
// Использование:
val jsonString = """{"userId":1,"id":1,"title":"delectus aut autem","completed":false}"""
val todo = JSONObject(jsonString).toTodo()
Для массивов можно сделать так:
import org.json.JSONArray
fun JSONArray.toTodoList(): List<Todo> {
val list = mutableListOf<Todo>()
for (i in 0 until length()) {
list.add(getJSONObject(i).toTodo())
}
return list
}
Плюсы и минусы
- Плюсы: не требует дополнительных зависимостей, подходит для простых случаев
- Минусы: много шаблонного кода, нет проверки типов на этапе компиляции, легко получить исключение при изменении структуры JSON
Этот подход хорош для быстрых прототипов или когда JSON имеет простую и стабильную структуру. Для серьёзных проектов всё же рекомендую kotlinx.serialization или Gson.
Ответов пока нет.
Войдите чтобы оставить ответ