# JSON 元素 The Kotlin serialization library also supports working with JSON at a structural level. You can use the [JsonElement](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-element/) API, to inspect, modify, and build JSON structures directly before converting them into a Kotlin type or a string. `JsonElement` has three direct subtypes that represent the core JSON structures: * [JsonPrimitive](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-primitive/) handles primitive JSON elements such as strings, numbers, booleans, and `null`. The `null` value is represented by a special subclass of `JsonPrimitive`, called [JsonNull](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-null/). Each `JsonPrimitive` stores a string representation of its value, which you can access through its [JsonPrimitive.content](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-primitive/content.html) property. * [JsonArray](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-array/) represents a JSON array. It's a Kotlin [List](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/) of `JsonElement` items. * [JsonObject](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-object/) represents a JSON object. It's a Kotlin [Map](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/#kotlin.collections.Map) with `String` keys and `JsonElement` values. ## Parse strings to JSON elements You can parse a string into a `JsonElement` to work with the JSON structure before converting it into a Kotlin type or a string. Use the [Json.parseToJsonElement()](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json/parse-to-json-element.html) function to parse the input into a JSON element tree without decoding or deserializing it: ```KOTLIN // 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 ``` ## Access the contents of JSON elements You can access the contents of a JSON element directly through the extension properties of the `JsonElement` API. These extension properties cast the element to a specific subtype and throw an `IllegalArgumentException` if the element doesn't have the expected JSON structure. The available extension properties are: * [jsonPrimitive](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/json-primitive.html) returns a `JsonPrimitive`. * [jsonArray](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/json-array.html) returns a `JsonArray`. * [jsonObject](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/json-object.html) returns a `JsonObject`. Similarly, [JsonPrimitive](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-primitive/) has extension properties for parsing the value as Kotlin primitive types, such as [int](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/int.html), [intOrNull](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/int-or-null.html), [long](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/long.html), and [longOrNull](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/long-or-null.html). Here's an example of how you can use these extension properties when processing JSON data with a known structure: ```KOTLIN // 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 ``` If you don't know the JSON structure in advance, you can check the element type and handle each `JsonElement` subtype explicitly. For example, you can use a helper function with a `when` expression: ```KOTLIN 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}" } ``` ## Create JSON elements You can create instances of specific `JsonElement` subtypes directly. To create a `JsonPrimitive`, use the `JsonPrimitive()` function: ```KOTLIN // 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 ``` You can create `JsonArray` and `JsonObject` elements either by directly calling their constructors or by using the builder functions: * To create a `JsonArray` from a `List`, use [JsonArray()](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-array/-json-array.html), or use the [buildJsonArray()](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/build-json-array.html) builder function. * To create a `JsonObject` from a `Map`, use [JsonObject()](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-object/-json-object.html), or use the [buildJsonObject()](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/build-json-object.html) builder function. The builder functions provide a DSL similar to [Kotlin's standard library collection builders](constructing-collections.html#create-with-collection-builder-functions) with JSON-specific overloads and inner builder functions. Here's an example that highlights the key features of the JSON builder DSLs: ```KOTLIN // 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 ``` ### Encode literal JSON content While the JSON specification doesn't restrict the size or precision of numbers, serializing numbers of arbitrary size with the `JsonPrimitive()` function might lead to some issues. For example, if you use [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/) for large numbers, the value might get truncated and you lose precision. If you use Kotlin/JVM [BigDecimal](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/java.math.-big-decimal/), the value stays precise, but `JsonPrimitive()` encodes the value as a string rather than as a number: ```KOTLIN // 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 ``` In this example, even though `pi` is defined as a number with 30 decimal places, the resulting JSON doesn't preserve that precision. The `Double` value is truncated to 15 decimal places, and the `String` value is wrapped in quotes, so it becomes a JSON string rather than a number. To avoid these issues, you can encode an arbitrary unquoted value, such as the string value of `pi` in this example, using the [JsonUnquotedLiteral()](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-unquoted-literal.html) function: ```KOTLIN // 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 ``` To decode `pi` back to a `BigDecimal`, extract the string content of the `JsonPrimitive`: ```KOTLIN // 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 ``` > **Tip:** > This example uses a `JsonPrimitive` for simplicity. For more reusable approaches, see [Json Transformations](serialization-transform-json.html). #### JSON null literal To avoid creating an inconsistent state, you can't encode the string `"null"` with the `JsonUnquotedLiteral()` function. If you try to do so, an exception is thrown: ```KOTLIN // 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 ``` To represent a JSON `null` literal value, use [JsonNull](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-null/): ```KOTLIN // Imports declarations from the serialization library import kotlinx.serialization.* import kotlinx.serialization.json.* //sampleStart fun main() { val possiblyNull = JsonNull println(possiblyNull) // null } //sampleEnd ``` ## Decode Json elements To decode an instance of the `JsonElement` class into a serializable object, use the [Json.decodeFromJsonElement()](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/decode-from-json-element.html) function: ```KOTLIN // 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(element) println(data) // Project(name=kotlinx.serialization, language=Kotlin) } //sampleEnd ``` ## What's next * Discover how to [transform JSON during serialization and deserialization](serialization-transform-json.html) for more control over your data. * Learn how to [serialize classes](serialization-customization-options.html) and how to modify the default behavior of the `@Serializable` annotation.