JSON-элементы
Библиотека сериализации Kotlin также поддерживает работу с JSON на структурном уровне. Вы можете использовать API JsonElement, чтобы изучать, изменять и создавать структуры JSON напрямую, прежде чем преобразовать их в тип Kotlin или строку.
JsonElement имеет три непосредственных подтипа, представляющих основные структуры JSON:
JsonPrimitiveобрабатывает примитивные элементы JSON, такие как строки, числа, логические значения иnull. Значениеnullпредставлено специальным подклассомJsonPrimitiveпод названиемJsonNull. КаждыйJsonPrimitiveхранит строковое представление своего значения, доступное через свойствоJsonPrimitive.content.JsonArrayпредставляет массив JSON. Это Kotlin-списокList, состоящий из элементовJsonElement.JsonObjectпредставляет объект JSON. Это Kotlin-словарьMapс ключамиStringи значениямиJsonElement.
Преобразование строк в JSON-элементы
Вы можете преобразовать строку в JsonElement, чтобы работать со структурой JSON до преобразования в тип Kotlin или строку.
Используйте функцию Json.parseToJsonElement(), чтобы преобразовать входные данные в дерево элементов JSON без декодирования или десериализации:
// Imports declarations from the serialization library
import kotlinx.serialization.*
import kotlinx.serialization.json.*
//sampleStart
fun main() {
val element = Json.parseToJsonElement("""
{"name":"kotlinx.serialization","language":"Kotlin"}
""")
// JsonElement.toString() gives you a valid JSON string
println(element)
// {"name":"kotlinx.serialization","language":"Kotlin"}
}
//sampleEnd
Доступ к содержимому JSON-элементов
Вы можете получить доступ к содержимому элемента JSON напрямую через свойства-расширения API JsonElement. Эти свойства-расширения преобразуют элемент в определённый подтип и выбрасывают IllegalArgumentException, если структура JSON элемента не соответствует ожидаемой.
Доступны следующие свойства-расширения:
jsonPrimitiveвозвращаетJsonPrimitive.jsonArrayвозвращаетJsonArray.jsonObjectвозвращаетJsonObject.
Аналогичным образом, у JsonPrimitive есть свойства-расширения для разбора значения в примитивные типы Kotlin, такие как int, intOrNull, long и longOrNull.
Вот пример использования этих свойств-расширений при обработке данных JSON с известной структурой:
// Imports declarations from the serialization library
import kotlinx.serialization.*
import kotlinx.serialization.json.*
//sampleStart
fun main() {
val element = Json.parseToJsonElement("""
{
"name": "kotlinx.serialization",
"forks": [{"votes": 42}, {"votes": 9000}, {}]
}
""")
val sum = element
// Accesses the forks key from the JsonObject
.jsonObject["forks"]!!
// Accesses the value as a JsonArray and sums the votes values from each JsonObject as Int
.jsonArray.sumOf { it.jsonObject["votes"]?.jsonPrimitive?.int ?: 0 }
println(sum)
// 9042
}
//sampleEnd
Если структура JSON заранее неизвестна, можно проверить тип элемента и обработать каждый подтип JsonElement явно. Например, можно использовать вспомогательную функцию с выражением when:
fun processElement(element: JsonElement): String = when (element) {
is JsonObject -> "JsonObject with keys: ${element.keys}"
is JsonArray -> "JsonArray with ${element.size} elements"
is JsonPrimitive -> "JsonPrimitive with content: ${element.content}"
}
Создание JSON-элементов
Вы можете напрямую создавать экземпляры определённых подтипов JsonElement.
Чтобы создать JsonPrimitive, используйте функцию JsonPrimitive():
// Imports declarations from the serialization library
import kotlinx.serialization.*
import kotlinx.serialization.json.*
//sampleStart
fun main() {
// Creates JsonPrimitive values from different Kotlin primitives
val number = JsonPrimitive(42)
val text = JsonPrimitive("kotlinx.serialization")
println(number)
// 42
println(text)
// "kotlinx.serialization"
}
//sampleEnd
Элементы JsonArray и JsonObject можно создавать, напрямую вызывая их конструкторы или используя функции-билдеры:
Чтобы создать
JsonArrayизList, используйтеJsonArray()или функцию-билдерbuildJsonArray().Чтобы создать
JsonObjectизMap, используйтеJsonObject()или функцию-билдерbuildJsonObject().
Функции-билдеры предоставляют DSL, похожий на функции-билдеры коллекций стандартной библиотеки Kotlin, с перегрузками для JSON и внутренними функциями-билдерами.
Вот пример, демонстрирующий основные возможности DSL-билдеров JSON:
// Imports declarations from the serialization library
import kotlinx.serialization.*
import kotlinx.serialization.json.*
//sampleStart
fun main() {
val element = buildJsonObject {
// Adds a simple key-value pair to the JsonObject
put("name", "kotlinx.serialization")
// Adds a nested JsonObject under the owner key
putJsonObject("owner") {
put("name", "kotlin")
}
// Adds a JsonArray with multiple JsonObjects
putJsonArray("forks") {
// Adds a JsonObject to the JsonArray
addJsonObject {
put("votes", 42)
}
addJsonObject {
put("votes", 9000)
}
}
}
// Prints the resulting JSON string
println(element)
// {"name":"kotlinx.serialization","owner":{"name":"kotlin"},"forks":[{"votes":42},{"votes":9000}]}
}
//sampleEnd
Кодирование литерального содержимого JSON
Хотя спецификация JSON не ограничивает размер или точность чисел, сериализация чисел произвольного размера с помощью функции JsonPrimitive() может привести к некоторым проблемам.
Например, если использовать Double для больших чисел, значение может быть усечено, и точность будет потеряна. Если использовать Kotlin/JVM BigDecimal, значение сохранит точность, но JsonPrimitive() закодирует его как строку, а не как число:
// Imports declarations from the serialization library
import kotlinx.serialization.*
import kotlinx.serialization.json.*
import java.math.BigDecimal
//sampleStart
val format = Json { prettyPrint = true }
fun main() {
val pi = BigDecimal("3.141592653589793238462643383279")
// Converts the BigDecimal to a Double, causing potential truncation
val piJsonDouble = JsonPrimitive(pi.toDouble())
// Converts the BigDecimal to a String, preserving the precision but treating it as a string in JSON
val piJsonString = JsonPrimitive(pi.toString())
val piObject = buildJsonObject {
put("pi_double", piJsonDouble)
put("pi_string", piJsonString)
}
println(format.encodeToString(piObject))
// "pi_double": 3.141592653589793,
// "pi_string": "3.141592653589793238462643383279"
}
//sampleEnd
В этом примере, хотя pi определено как число с 30 знаками после запятой, итоговый JSON не сохраняет эту точность. Значение Double усечено до 15 знаков после запятой, а значение String заключено в кавычки и поэтому становится строкой JSON, а не числом.
Чтобы избежать этих проблем, можно закодировать произвольное значение без кавычек, например строковое значение pi в этом примере, с помощью функции JsonUnquotedLiteral():
// Imports declarations from the serialization library
import kotlinx.serialization.*
import kotlinx.serialization.json.*
import java.math.BigDecimal
//sampleStart
val format = Json { prettyPrint = true }
fun main() {
val pi = BigDecimal("3.141592653589793238462643383279")
// Encodes the raw JSON content using JsonUnquotedLiteral()
@OptIn(ExperimentalSerializationApi::class)
val piJsonLiteral = JsonUnquotedLiteral(pi.toString())
// Converts to Double and String
val piJsonDouble = JsonPrimitive(pi.toDouble())
val piJsonString = JsonPrimitive(pi.toString())
val piObject = buildJsonObject {
put("pi_literal", piJsonLiteral)
put("pi_double", piJsonDouble)
put("pi_string", piJsonString)
}
// pi_literal now accurately matches the value defined
println(format.encodeToString(piObject))
// "pi_literal": 3.141592653589793238462643383279,
// "pi_double": 3.141592653589793,
// "pi_string": "3.141592653589793238462643383279"
}
//sampleEnd
Чтобы декодировать pi обратно в BigDecimal, извлеките строковое содержимое из JsonPrimitive:
// Imports declarations from the serialization library
import kotlinx.serialization.*
import kotlinx.serialization.json.*
import java.math.BigDecimal
//sampleStart
fun main() {
val piObjectJson = """
{
"pi_literal": 3.141592653589793238462643383279
}
""".trimIndent()
// Decodes the JSON string into a JsonObject
val piObject: JsonObject = Json.decodeFromString(piObjectJson)
// Extracts the string content from the JsonPrimitive
val piJsonLiteral = piObject["pi_literal"]!!.jsonPrimitive.content
// Converts the string to a BigDecimal
val pi = BigDecimal(piJsonLiteral)
// Prints the decoded value of pi, preserving all 30 decimal places
println(pi)
// 3.141592653589793238462643383279
}
//sampleEnd
Литерал JSON null
Чтобы избежать создания некорректного состояния, нельзя кодировать строку "null" с помощью функции JsonUnquotedLiteral(). При попытке это сделать будет выброшено исключение:
// Imports declarations from the serialization library
import kotlinx.serialization.*
import kotlinx.serialization.json.*
//sampleStart
@OptIn(ExperimentalSerializationApi::class)
fun main() {
JsonUnquotedLiteral("null")
// Exception in thread "main" kotlinx.serialization.json.internal.JsonEncodingException
}
//sampleEnd
Чтобы представить литеральное значение JSON null, используйте JsonNull:
// Imports declarations from the serialization library
import kotlinx.serialization.*
import kotlinx.serialization.json.*
//sampleStart
fun main() {
val possiblyNull = JsonNull
println(possiblyNull)
// null
}
//sampleEnd
Декодирование элементов JSON
Чтобы декодировать экземпляр класса JsonElement в сериализуемый объект, используйте функцию Json.decodeFromJsonElement():
// Imports declarations from the serialization library
import kotlinx.serialization.*
import kotlinx.serialization.json.*
//sampleStart
@Serializable
data class Project(val name: String, val language: String)
fun main() {
val element = buildJsonObject {
put("name", "kotlinx.serialization")
put("language", "Kotlin")
}
// Decodes the JsonElement into a Project object
val data = Json.decodeFromJsonElement<Project>(element)
println(data)
// Project(name=kotlinx.serialization, language=Kotlin)
}
//sampleEnd
Что дальше
Узнайте, как преобразовывать JSON при сериализации и десериализации, чтобы лучше контролировать данные.
Узнайте, как сериализовать классы и изменять поведение аннотации
@Serializableпо умолчанию.
© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/serialization-json-elements.html