xref: /aosp_15_r20/external/kotlinx.serialization/docs/json.md (revision 57b5a4a64c534cf7f27ac9427ceab07f3d8ed3d8)
1<!--- TEST_NAME JsonTest -->
2
3# JSON features
4
5This is the fifth chapter of the [Kotlin Serialization Guide](serialization-guide.md).
6In this chapter, we'll walk through features of [JSON](https://www.json.org/json-en.html) serialization available in the [Json] class.
7
8**Table of contents**
9
10<!--- TOC -->
11
12* [Json configuration](#json-configuration)
13  * [Pretty printing](#pretty-printing)
14  * [Lenient parsing](#lenient-parsing)
15  * [Ignoring unknown keys](#ignoring-unknown-keys)
16  * [Alternative Json names](#alternative-json-names)
17  * [Coercing input values](#coercing-input-values)
18  * [Encoding defaults](#encoding-defaults)
19  * [Explicit nulls](#explicit-nulls)
20  * [Allowing structured map keys](#allowing-structured-map-keys)
21  * [Allowing special floating-point values](#allowing-special-floating-point-values)
22  * [Class discriminator for polymorphism](#class-discriminator-for-polymorphism)
23  * [Class discriminator output mode](#class-discriminator-output-mode)
24  * [Decoding enums in a case-insensitive manner](#decoding-enums-in-a-case-insensitive-manner)
25  * [Global naming strategy](#global-naming-strategy)
26* [Json elements](#json-elements)
27  * [Parsing to Json element](#parsing-to-json-element)
28  * [Types of Json elements](#types-of-json-elements)
29  * [Json element builders](#json-element-builders)
30  * [Decoding Json elements](#decoding-json-elements)
31  * [Encoding literal Json content (experimental)](#encoding-literal-json-content-experimental)
32    * [Serializing large decimal numbers](#serializing-large-decimal-numbers)
33    * [Using `JsonUnquotedLiteral` to create a literal unquoted value of `null` is forbidden](#using-jsonunquotedliteral-to-create-a-literal-unquoted-value-of-null-is-forbidden)
34* [Json transformations](#json-transformations)
35  * [Array wrapping](#array-wrapping)
36  * [Array unwrapping](#array-unwrapping)
37  * [Manipulating default values](#manipulating-default-values)
38  * [Content-based polymorphic deserialization](#content-based-polymorphic-deserialization)
39  * [Under the hood (experimental)](#under-the-hood-experimental)
40  * [Maintaining custom JSON attributes](#maintaining-custom-json-attributes)
41
42<!--- END -->
43
44## Json configuration
45
46The default [Json] implementation is quite strict with respect to invalid inputs. It enforces Kotlin type safety and
47restricts Kotlin values that can be serialized so that the resulting JSON representations are standard.
48Many non-standard JSON features are supported by creating a custom instance of a JSON _format_.
49
50To use a custom JSON format configuration, create your own [Json] class instance from an existing
51instance, such as a default `Json` object, using the [Json()] builder function. Specify parameter values
52in the parentheses via the [JsonBuilder] DSL. The resulting `Json` format instance is immutable and thread-safe;
53it can be simply stored in a top-level property.
54
55> We recommend that you store and reuse custom instances of formats for performance reasons because format implementations
56> may cache format-specific additional information about the classes they serialize.
57
58This chapter shows configuration features that [Json] supports.
59
60<!--- INCLUDE .*-json-.*
61import kotlinx.serialization.*
62import kotlinx.serialization.json.*
63-->
64
65### Pretty printing
66
67By default, the [Json] output is a single line. You can configure it to pretty print the output (that is, add indentations
68and line breaks for better readability) by setting the [prettyPrint][JsonBuilder.prettyPrint] property to `true`:
69
70```kotlin
71val format = Json { prettyPrint = true }
72
73@Serializable
74data class Project(val name: String, val language: String)
75
76fun main() {
77    val data = Project("kotlinx.serialization", "Kotlin")
78    println(format.encodeToString(data))
79}
80```
81
82> You can get the full code [here](../guide/example/example-json-01.kt).
83
84It gives the following nice result:
85
86```text
87{
88    "name": "kotlinx.serialization",
89    "language": "Kotlin"
90}
91```
92
93<!--- TEST -->
94
95### Lenient parsing
96
97By default, [Json] parser enforces various JSON restrictions to be as specification-compliant as possible
98(see [RFC-4627]). Particularly, keys and string literals must be quoted. Those restrictions can be relaxed with
99the [isLenient][JsonBuilder.isLenient] property. With `isLenient = true`, you can parse quite freely-formatted data:
100
101```kotlin
102val format = Json { isLenient = true }
103
104enum class Status { SUPPORTED }
105
106@Serializable
107data class Project(val name: String, val status: Status, val votes: Int)
108
109fun main() {
110    val data = format.decodeFromString<Project>("""
111        {
112            name   : kotlinx.serialization,
113            status : SUPPORTED,
114            votes  : "9000"
115        }
116    """)
117    println(data)
118}
119```
120
121> You can get the full code [here](../guide/example/example-json-02.kt).
122
123You get the object, even though all keys of the source JSON, string, and enum values are unquoted, while an
124integer is quoted:
125
126```text
127Project(name=kotlinx.serialization, status=SUPPORTED, votes=9000)
128```
129
130<!--- TEST -->
131
132### Ignoring unknown keys
133
134JSON format is often used to read the output of third-party services or in other dynamic environments where
135new properties can be added during the API evolution. By default, unknown keys encountered during deserialization produce an error.
136You can avoid this and just ignore such keys by setting the [ignoreUnknownKeys][JsonBuilder.ignoreUnknownKeys] property
137to `true`:
138
139```kotlin
140val format = Json { ignoreUnknownKeys = true }
141
142@Serializable
143data class Project(val name: String)
144
145fun main() {
146    val data = format.decodeFromString<Project>("""
147        {"name":"kotlinx.serialization","language":"Kotlin"}
148    """)
149    println(data)
150}
151```
152
153> You can get the full code [here](../guide/example/example-json-03.kt).
154
155It decodes the object despite the fact that the `Project` class doesn't have the `language` property:
156
157```text
158Project(name=kotlinx.serialization)
159```
160
161<!--- TEST -->
162
163### Alternative Json names
164
165It's not a rare case when JSON fields are renamed due to a schema version change.
166You can use the [`@SerialName` annotation](basic-serialization.md#serial-field-names) to change the name of a JSON field,
167but such renaming blocks the ability to decode data with the old name.
168To support multiple JSON names for the one Kotlin property, there is the [JsonNames] annotation:
169
170```kotlin
171@Serializable
172data class Project(@JsonNames("title") val name: String)
173
174fun main() {
175  val project = Json.decodeFromString<Project>("""{"name":"kotlinx.serialization"}""")
176  println(project)
177  val oldProject = Json.decodeFromString<Project>("""{"title":"kotlinx.coroutines"}""")
178  println(oldProject)
179}
180```
181
182> You can get the full code [here](../guide/example/example-json-04.kt).
183
184As you can see, both `name` and `title` Json fields correspond to `name` property:
185
186```text
187Project(name=kotlinx.serialization)
188Project(name=kotlinx.coroutines)
189```
190
191Support for [JsonNames] annotation is controlled by the [JsonBuilder.useAlternativeNames] flag.
192Unlike most of the configuration flags, this one is enabled by default and does not need attention
193unless you want to do some fine-tuning.
194
195<!--- TEST -->
196
197### Coercing input values
198
199JSON formats that from third parties can evolve, sometimes changing the field types.
200This can lead to exceptions during decoding when the actual values do not match the expected values.
201The default [Json] implementation is strict with respect to input types as was demonstrated in
202the [Type safety is enforced](basic-serialization.md#type-safety-is-enforced) section. You can relax this restriction
203using the [coerceInputValues][JsonBuilder.coerceInputValues] property.
204
205This property only affects decoding. It treats a limited subset of invalid input values as if the
206corresponding property was missing and uses the default value of the corresponding property instead.
207The current list of supported invalid values is:
208
209* `null` inputs for non-nullable types
210* unknown values for enums
211
212> This list may be expanded in the future, so that [Json] instance configured with this property becomes even more
213> permissive to invalid value in the input, replacing them with defaults.
214
215See the example from the [Type safety is enforced](basic-serialization.md#type-safety-is-enforced) section:
216
217```kotlin
218val format = Json { coerceInputValues = true }
219
220@Serializable
221data class Project(val name: String, val language: String = "Kotlin")
222
223fun main() {
224    val data = format.decodeFromString<Project>("""
225        {"name":"kotlinx.serialization","language":null}
226    """)
227    println(data)
228}
229```
230
231> You can get the full code [here](../guide/example/example-json-05.kt).
232
233The invalid `null` value for the `language` property was coerced into the default value:
234
235```text
236Project(name=kotlinx.serialization, language=Kotlin)
237```
238
239<!--- TEST -->
240
241
242### Encoding defaults
243
244Default values of properties are not encoded by default because they will be assigned to missing fields during decoding anyway.
245See the [Defaults are not encoded](basic-serialization.md#defaults-are-not-encoded-by-default) section for details and an example.
246This is especially useful for nullable properties with null defaults and avoids writing the corresponding null values.
247The default behavior can be changed by setting the [encodeDefaults][JsonBuilder.encodeDefaults] property to `true`:
248
249```kotlin
250val format = Json { encodeDefaults = true }
251
252@Serializable
253class Project(
254    val name: String,
255    val language: String = "Kotlin",
256    val website: String? = null
257)
258
259fun main() {
260    val data = Project("kotlinx.serialization")
261    println(format.encodeToString(data))
262}
263```
264
265> You can get the full code [here](../guide/example/example-json-06.kt).
266
267It produces the following output which encodes all the property values including the default ones:
268
269```text
270{"name":"kotlinx.serialization","language":"Kotlin","website":null}
271```
272
273<!--- TEST -->
274
275### Explicit nulls
276
277By default, all `null` values are encoded into JSON strings, but in some cases you may want to omit them.
278The encoding of `null` values can be controlled with the [explicitNulls][JsonBuilder.explicitNulls] property.
279
280If you set property to `false`, fields with `null` values are not encoded into JSON even if the property does not have a
281default `null` value. When decoding such JSON, the absence of a property value is treated as `null` for nullable properties
282without a default value.
283
284```kotlin
285val format = Json { explicitNulls = false }
286
287@Serializable
288data class Project(
289    val name: String,
290    val language: String,
291    val version: String? = "1.2.2",
292    val website: String?,
293    val description: String? = null
294)
295
296fun main() {
297    val data = Project("kotlinx.serialization", "Kotlin", null, null, null)
298    val json = format.encodeToString(data)
299    println(json)
300    println(format.decodeFromString<Project>(json))
301}
302```
303
304> You can get the full code [here](../guide/example/example-json-07.kt).
305
306As you can see, `version`, `website` and `description` fields are not present in output JSON on the first line.
307After decoding, the missing nullable property `website` without a default values has received a `null` value,
308while nullable properties `version` and `description` are filled with their default values:
309
310```text
311{"name":"kotlinx.serialization","language":"Kotlin"}
312Project(name=kotlinx.serialization, language=Kotlin, version=1.2.2, website=null, description=null)
313```
314
315`explicitNulls` is `true` by default as it is the default behavior across different versions of the library.
316
317<!--- TEST -->
318
319### Allowing structured map keys
320
321JSON format does not natively support the concept of a map with structured keys. Keys in JSON objects
322are strings and can be used to represent only primitives or enums by default.
323You can enable non-standard support for structured keys with
324the [allowStructuredMapKeys][JsonBuilder.allowStructuredMapKeys] property.
325
326This is how you can serialize a map with keys of a user-defined class:
327
328```kotlin
329val format = Json { allowStructuredMapKeys = true }
330
331@Serializable
332data class Project(val name: String)
333
334fun main() {
335    val map = mapOf(
336        Project("kotlinx.serialization") to "Serialization",
337        Project("kotlinx.coroutines") to "Coroutines"
338    )
339    println(format.encodeToString(map))
340}
341```
342
343> You can get the full code [here](../guide/example/example-json-08.kt).
344
345The map with structured keys gets represented as JSON array with the following items: `[key1, value1, key2, value2,...]`.
346
347```text
348[{"name":"kotlinx.serialization"},"Serialization",{"name":"kotlinx.coroutines"},"Coroutines"]
349```
350
351<!--- TEST -->
352
353### Allowing special floating-point values
354
355By default, special floating-point values like [Double.NaN] and infinities are not supported in JSON because
356the JSON specification prohibits it.
357You can enable their encoding using the [allowSpecialFloatingPointValues][JsonBuilder.allowSpecialFloatingPointValues]
358property:
359
360```kotlin
361val format = Json { allowSpecialFloatingPointValues = true }
362
363@Serializable
364class Data(
365    val value: Double
366)
367
368fun main() {
369    val data = Data(Double.NaN)
370    println(format.encodeToString(data))
371}
372```
373
374> You can get the full code [here](../guide/example/example-json-09.kt).
375
376This example produces the following non-stardard JSON output, yet it is a widely used encoding for
377special values in JVM world:
378
379```text
380{"value":NaN}
381```
382
383<!--- TEST -->
384
385### Class discriminator for polymorphism
386
387A key name that specifies a type when you have a polymorphic data can be specified
388in the [classDiscriminator][JsonBuilder.classDiscriminator] property:
389
390```kotlin
391val format = Json { classDiscriminator = "#class" }
392
393@Serializable
394sealed class Project {
395    abstract val name: String
396}
397
398@Serializable
399@SerialName("owned")
400class OwnedProject(override val name: String, val owner: String) : Project()
401
402fun main() {
403    val data: Project = OwnedProject("kotlinx.coroutines", "kotlin")
404    println(format.encodeToString(data))
405}
406```
407
408> You can get the full code [here](../guide/example/example-json-10.kt).
409
410In combination with an explicitly specified [SerialName] of the class it provides full
411control over the resulting JSON object:
412
413```text
414{"#class":"owned","name":"kotlinx.coroutines","owner":"kotlin"}
415```
416
417<!--- TEST -->
418
419It is also possible to specify different class discriminators for different hierarchies. Instead of Json instance property, use [JsonClassDiscriminator] annotation directly on base serializable class:
420
421```kotlin
422@Serializable
423@JsonClassDiscriminator("message_type")
424sealed class Base
425```
426
427This annotation is _inheritable_, so all subclasses of `Base` will have the same discriminator:
428
429```kotlin
430@Serializable // Class discriminator is inherited from Base
431sealed class ErrorClass: Base()
432```
433
434> To learn more about inheritable serial annotations, see documentation for [InheritableSerialInfo].
435
436Note that it is not possible to explicitly specify different class discriminators in subclasses of `Base`. Only hierarchies with empty intersections can have different discriminators.
437
438Discriminator specified in the annotation has priority over discriminator in Json configuration:
439
440<!--- INCLUDE
441
442@Serializable
443data class Message(val message: Base, val error: ErrorClass?)
444
445@Serializable
446@SerialName("my.app.BaseMessage")
447data class BaseMessage(val message: String) : Base()
448
449@Serializable
450@SerialName("my.app.GenericError")
451data class GenericError(@SerialName("error_code") val errorCode: Int) : ErrorClass()
452-->
453
454```kotlin
455
456val format = Json { classDiscriminator = "#class" }
457
458fun main() {
459    val data = Message(BaseMessage("not found"), GenericError(404))
460    println(format.encodeToString(data))
461}
462```
463
464> You can get the full code [here](../guide/example/example-json-11.kt).
465
466As you can see, discriminator from the `Base` class is used:
467
468```text
469{"message":{"message_type":"my.app.BaseMessage","message":"not found"},"error":{"message_type":"my.app.GenericError","error_code":404}}
470```
471
472<!--- TEST -->
473
474### Class discriminator output mode
475
476Class discriminator provides information for serializing and deserializing [polymorphic class hierarchies](polymorphism.md#sealed-classes).
477As shown above, it is only added for polymorphic classes by default.
478In case you want to encode more or less information for various third party APIs about types in the output, it is possible to control
479addition of the class discriminator with the [JsonBuilder.classDiscriminatorMode] property.
480
481For example, [ClassDiscriminatorMode.NONE] does not add class discriminator at all, in case the receiving party is not interested in Kotlin types:
482
483```kotlin
484val format = Json { classDiscriminatorMode = ClassDiscriminatorMode.NONE }
485
486@Serializable
487sealed class Project {
488    abstract val name: String
489}
490
491@Serializable
492class OwnedProject(override val name: String, val owner: String) : Project()
493
494fun main() {
495    val data: Project = OwnedProject("kotlinx.coroutines", "kotlin")
496    println(format.encodeToString(data))
497}
498```
499
500> You can get the full code [here](../guide/example/example-json-12.kt).
501
502Note that it would be impossible to deserialize this output back with kotlinx.serialization.
503
504```text
505{"name":"kotlinx.coroutines","owner":"kotlin"}
506```
507
508Two other available values are [ClassDiscriminatorMode.POLYMORPHIC] (default behavior) and [ClassDiscriminatorMode.ALL_JSON_OBJECTS] (adds discriminator whenever possible).
509Consult their documentation for details.
510
511<!--- TEST -->
512
513### Decoding enums in a case-insensitive manner
514
515[Kotlin's naming policy recommends](https://kotlinlang.org/docs/coding-conventions.html#property-names) naming enum values
516using either uppercase underscore-separated names or upper camel case names.
517[Json] uses exact Kotlin enum values names for decoding by default.
518However, sometimes third-party JSONs have such values named in lowercase or some mixed case.
519In this case, it is possible to decode enum values in a case-insensitive manner using [JsonBuilder.decodeEnumsCaseInsensitive] property:
520
521```kotlin
522val format = Json { decodeEnumsCaseInsensitive = true }
523
524enum class Cases { VALUE_A, @JsonNames("Alternative") VALUE_B }
525
526@Serializable
527data class CasesList(val cases: List<Cases>)
528
529fun main() {
530  println(format.decodeFromString<CasesList>("""{"cases":["value_A", "alternative"]}"""))
531}
532```
533
534> You can get the full code [here](../guide/example/example-json-13.kt).
535
536It affects serial names as well as alternative names specified with [JsonNames] annotation, so both values are successfully decoded:
537
538```text
539CasesList(cases=[VALUE_A, VALUE_B])
540```
541
542This property does not affect encoding in any way.
543
544<!--- TEST -->
545
546### Global naming strategy
547
548If properties' names in Json input are different from Kotlin ones, it is recommended to specify the name
549for each property explicitly using [`@SerialName` annotation](basic-serialization.md#serial-field-names).
550However, there are certain situations where transformation should be applied to every serial name — such as migration
551from other frameworks or legacy codebase. For that cases, it is possible to specify a [namingStrategy][JsonBuilder.namingStrategy]
552for a [Json] instance. `kotlinx.serialization` provides one strategy implementation out of the box, the [JsonNamingStrategy.SnakeCase](https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-naming-strategy/-builtins/-snake-case.html):
553
554```kotlin
555@Serializable
556data class Project(val projectName: String, val projectOwner: String)
557
558val format = Json { namingStrategy = JsonNamingStrategy.SnakeCase }
559
560fun main() {
561    val project = format.decodeFromString<Project>("""{"project_name":"kotlinx.coroutines", "project_owner":"Kotlin"}""")
562    println(format.encodeToString(project.copy(projectName = "kotlinx.serialization")))
563}
564```
565
566> You can get the full code [here](../guide/example/example-json-14.kt).
567
568As you can see, both serialization and deserialization work as if all serial names are transformed from camel case to snake case:
569
570```text
571{"project_name":"kotlinx.serialization","project_owner":"Kotlin"}
572```
573
574There are some caveats one should remember while dealing with a [JsonNamingStrategy]:
575
576* Due to the nature of the `kotlinx.serialization` framework, naming strategy transformation is applied to all properties regardless
577of whether their serial name was taken from the property name or provided by [SerialName] annotation.
578Effectively, it means one cannot avoid transformation by explicitly specifying the serial name. To be able to deserialize
579non-transformed names, [JsonNames] annotation can be used instead.
580
581* Collision of the transformed name with any other (transformed) properties serial names or any alternative names
582specified with [JsonNames] will lead to a deserialization exception.
583
584* Global naming strategies are very implicit: by looking only at the definition of the class,
585it is impossible to determine which names it will have in the serialized form.
586As a consequence, naming strategies are not friendly to actions like Find Usages/Rename in IDE, full-text search by grep, etc.
587For them, the original name and the transformed are two different things;
588changing one without the other may introduce bugs in many unexpected ways and lead to greater maintenance efforts for code with global naming strategies.
589
590Therefore, one should carefully weigh the pros and cons before considering adding global naming strategies to an application.
591
592<!--- TEST -->
593
594## Json elements
595
596Aside from direct conversions between strings and JSON objects, Kotlin serialization offers APIs that allow
597other ways of working with JSON in the code. For example, you might need to tweak the data before it can parse
598or otherwise work with such an unstructured data that it does not readily fit into the typesafe world of Kotlin
599serialization.
600
601The main concept in this part of the library is [JsonElement]. Read on to learn what you can do with it.
602
603### Parsing to Json element
604
605A string can be _parsed_ into an instance of [JsonElement] with the [Json.parseToJsonElement] function.
606It is called neither decoding nor deserialization because none of that happens in the process.
607It just parses a JSON and forms an object representing it:
608
609```kotlin
610fun main() {
611    val element = Json.parseToJsonElement("""
612        {"name":"kotlinx.serialization","language":"Kotlin"}
613    """)
614    println(element)
615}
616```
617
618> You can get the full code [here](../guide/example/example-json-15.kt).
619
620A `JsonElement` prints itself as a valid JSON:
621
622```text
623{"name":"kotlinx.serialization","language":"Kotlin"}
624```
625
626<!--- TEST -->
627
628### Types of Json elements
629
630A [JsonElement] class has three direct subtypes, closely following JSON grammar:
631
632* [JsonPrimitive] represents primitive JSON elements, such as string, number, boolean, and null.
633  Each primitive has a simple string [content][JsonPrimitive.content]. There is also a
634  [JsonPrimitive()] constructor function overloaded to accept various primitive Kotlin types and
635  to convert them to `JsonPrimitive`.
636
637* [JsonArray] represents a JSON `[...]` array. It is a Kotlin [List] of `JsonElement` items.
638
639* [JsonObject] represents a JSON `{...}` object. It is a Kotlin [Map] from `String` keys to `JsonElement` values.
640
641The `JsonElement` class has extensions that cast it to its corresponding subtypes:
642[jsonPrimitive][_jsonPrimitive], [jsonArray][_jsonArray], [jsonObject][_jsonObject]. The `JsonPrimitive` class,
643in turn, provides converters to Kotlin primitive types: [int], [intOrNull], [long], [longOrNull],
644and similar ones for other types. This is how you can use them for processing JSON whose structure you know:
645
646```kotlin
647fun main() {
648    val element = Json.parseToJsonElement("""
649        {
650            "name": "kotlinx.serialization",
651            "forks": [{"votes": 42}, {"votes": 9000}, {}]
652        }
653    """)
654    val sum = element
655        .jsonObject["forks"]!!
656        .jsonArray.sumOf { it.jsonObject["votes"]?.jsonPrimitive?.int ?: 0 }
657    println(sum)
658}
659```
660
661> You can get the full code [here](../guide/example/example-json-16.kt).
662
663The above example sums `votes` in all objects in the `forks` array, ignoring the objects that have no `votes`:
664
665```text
6669042
667```
668
669<!--- TEST -->
670
671Note that the execution will fail if the structure of the data is otherwise different.
672
673### Json element builders
674
675You can construct instances of specific [JsonElement] subtypes using the respective builder functions
676[buildJsonArray] and [buildJsonObject]. They provide a DSL to define the resulting JSON structure. It
677is similar to Kotlin standard library collection builders, but with a JSON-specific convenience
678of more type-specific overloads and inner builder functions. The following example shows
679all the key features:
680
681```kotlin
682fun main() {
683    val element = buildJsonObject {
684        put("name", "kotlinx.serialization")
685        putJsonObject("owner") {
686            put("name", "kotlin")
687        }
688        putJsonArray("forks") {
689            addJsonObject {
690                put("votes", 42)
691            }
692            addJsonObject {
693                put("votes", 9000)
694            }
695        }
696    }
697    println(element)
698}
699```
700
701> You can get the full code [here](../guide/example/example-json-17.kt).
702
703As a result, you get a proper JSON string:
704
705```text
706{"name":"kotlinx.serialization","owner":{"name":"kotlin"},"forks":[{"votes":42},{"votes":9000}]}
707```
708
709<!--- TEST -->
710
711### Decoding Json elements
712
713An instance of the [JsonElement] class can be decoded into a serializable object using
714the [Json.decodeFromJsonElement] function:
715
716```kotlin
717@Serializable
718data class Project(val name: String, val language: String)
719
720fun main() {
721    val element = buildJsonObject {
722        put("name", "kotlinx.serialization")
723        put("language", "Kotlin")
724    }
725    val data = Json.decodeFromJsonElement<Project>(element)
726    println(data)
727}
728```
729
730> You can get the full code [here](../guide/example/example-json-18.kt).
731
732The result is exactly what you would expect:
733
734```text
735Project(name=kotlinx.serialization, language=Kotlin)
736```
737
738<!--- TEST -->
739
740### Encoding literal Json content (experimental)
741
742> This functionality is experimental and requires opting-in to [the experimental Kotlinx Serialization API](compatibility.md#experimental-api).
743
744In some cases it might be necessary to encode an arbitrary unquoted value.
745This can be achieved with [JsonUnquotedLiteral].
746
747#### Serializing large decimal numbers
748
749The JSON specification does not restrict the size or precision of numbers, however it is not possible to serialize
750numbers of arbitrary size or precision using [JsonPrimitive()].
751
752If [Double] is used, then the numbers are limited in precision, meaning that large numbers are truncated.
753When using Kotlin/JVM [BigDecimal] can be used instead, but [JsonPrimitive()] will encode the value as a string, not a
754number.
755
756```kotlin
757import java.math.BigDecimal
758
759val format = Json { prettyPrint = true }
760
761fun main() {
762    val pi = BigDecimal("3.141592653589793238462643383279")
763
764    val piJsonDouble = JsonPrimitive(pi.toDouble())
765    val piJsonString = JsonPrimitive(pi.toString())
766
767    val piObject = buildJsonObject {
768        put("pi_double", piJsonDouble)
769        put("pi_string", piJsonString)
770    }
771
772    println(format.encodeToString(piObject))
773}
774```
775
776> You can get the full code [here](../guide/example/example-json-19.kt).
777
778Even though `pi` was defined as a number with 30 decimal places, the resulting JSON does not reflect this.
779The [Double] value is truncated to 15 decimal places, and the String is wrapped in quotes - which is not a JSON number.
780
781```text
782{
783    "pi_double": 3.141592653589793,
784    "pi_string": "3.141592653589793238462643383279"
785}
786```
787
788<!--- TEST -->
789
790To avoid precision loss, the string value of `pi` can be encoded using [JsonUnquotedLiteral].
791
792```kotlin
793import java.math.BigDecimal
794
795val format = Json { prettyPrint = true }
796
797fun main() {
798    val pi = BigDecimal("3.141592653589793238462643383279")
799
800    // use JsonUnquotedLiteral to encode raw JSON content
801    val piJsonLiteral = JsonUnquotedLiteral(pi.toString())
802
803    val piJsonDouble = JsonPrimitive(pi.toDouble())
804    val piJsonString = JsonPrimitive(pi.toString())
805
806    val piObject = buildJsonObject {
807        put("pi_literal", piJsonLiteral)
808        put("pi_double", piJsonDouble)
809        put("pi_string", piJsonString)
810    }
811
812    println(format.encodeToString(piObject))
813}
814```
815
816> You can get the full code [here](../guide/example/example-json-20.kt).
817
818`pi_literal` now accurately matches the value defined.
819
820```text
821{
822    "pi_literal": 3.141592653589793238462643383279,
823    "pi_double": 3.141592653589793,
824    "pi_string": "3.141592653589793238462643383279"
825}
826```
827
828<!--- TEST -->
829
830To decode `pi` back to a [BigDecimal], the string content of the [JsonPrimitive] can be used.
831
832(This demonstration uses a [JsonPrimitive] for simplicity. For a more re-usable method of handling serialization, see
833[Json Transformations](#json-transformations) below.)
834
835
836```kotlin
837import java.math.BigDecimal
838
839fun main() {
840    val piObjectJson = """
841          {
842              "pi_literal": 3.141592653589793238462643383279
843          }
844      """.trimIndent()
845
846    val piObject: JsonObject = Json.decodeFromString(piObjectJson)
847
848    val piJsonLiteral = piObject["pi_literal"]!!.jsonPrimitive.content
849
850    val pi = BigDecimal(piJsonLiteral)
851
852    println(pi)
853}
854```
855
856> You can get the full code [here](../guide/example/example-json-21.kt).
857
858The exact value of `pi` is decoded, with all 30 decimal places of precision that were in the source JSON.
859
860```text
8613.141592653589793238462643383279
862```
863
864<!--- TEST -->
865
866#### Using `JsonUnquotedLiteral` to create a literal unquoted value of `null` is forbidden
867
868To avoid creating an inconsistent state, encoding a String equal to `"null"` is forbidden.
869Use [JsonNull] or [JsonPrimitive] instead.
870
871```kotlin
872fun main() {
873    // caution: creating null with JsonUnquotedLiteral will cause an exception!
874    JsonUnquotedLiteral("null")
875}
876```
877
878> You can get the full code [here](../guide/example/example-json-22.kt).
879
880```text
881Exception in thread "main" kotlinx.serialization.json.internal.JsonEncodingException: Creating a literal unquoted value of 'null' is forbidden. If you want to create JSON null literal, use JsonNull object, otherwise, use JsonPrimitive
882```
883
884<!--- TEST LINES_START -->
885
886
887## Json transformations
888
889To affect the shape and contents of JSON output after serialization, or adapt input to deserialization,
890it is possible to write a [custom serializer](serializers.md). However, it may be inconvenient to
891carefully follow [Encoder] and [Decoder] calling conventions, especially for relatively small and easy tasks.
892For that purpose, Kotlin serialization provides an API that can reduce the burden of implementing a custom
893serializer to a problem of manipulating a Json elements tree.
894
895We recommend that you get familiar with the [Serializers](serializers.md) chapter: among other things, it
896explains how custom serializers are bound to classes.
897
898Transformation capabilities are provided by the abstract [JsonTransformingSerializer] class which implements [KSerializer].
899Instead of direct interaction with `Encoder` or `Decoder`, this class asks you to supply transformations for JSON tree
900represented by the [JsonElement] class using the`transformSerialize` and
901`transformDeserialize` methods. Let's take a look at the examples.
902
903### Array wrapping
904
905The first example is an implementation of JSON array wrapping for lists.
906
907Consider a REST API that returns a JSON array of `User` objects, or a single object (not wrapped into an array) if there
908is only one element in the result.
909
910In the data model, use the [`@Serializable`][Serializable] annotation to specify a custom serializer for a
911`users: List<User>` property.
912
913<!--- INCLUDE
914import kotlinx.serialization.builtins.*
915-->
916
917```kotlin
918@Serializable
919data class Project(
920    val name: String,
921    @Serializable(with = UserListSerializer::class)
922    val users: List<User>
923)
924
925@Serializable
926data class User(val name: String)
927```
928
929Since this example covers only the deserialization case, you can implement `UserListSerializer` and override only the
930`transformDeserialize` function. The `JsonTransformingSerializer` constructor takes an original serializer
931as parameter (this approach is shown in the section [Constructing collection serializers](serializers.md#constructing-collection-serializers)):
932
933```kotlin
934object UserListSerializer : JsonTransformingSerializer<List<User>>(ListSerializer(User.serializer())) {
935    // If response is not an array, then it is a single object that should be wrapped into the array
936    override fun transformDeserialize(element: JsonElement): JsonElement =
937        if (element !is JsonArray) JsonArray(listOf(element)) else element
938}
939```
940
941Now you can test the code with a JSON array or a single JSON object as inputs.
942
943```kotlin
944fun main() {
945    println(Json.decodeFromString<Project>("""
946        {"name":"kotlinx.serialization","users":{"name":"kotlin"}}
947    """))
948    println(Json.decodeFromString<Project>("""
949        {"name":"kotlinx.serialization","users":[{"name":"kotlin"},{"name":"jetbrains"}]}
950    """))
951}
952```
953
954> You can get the full code [here](../guide/example/example-json-23.kt).
955
956The output shows that both cases are correctly deserialized into a Kotlin [List].
957
958```text
959Project(name=kotlinx.serialization, users=[User(name=kotlin)])
960Project(name=kotlinx.serialization, users=[User(name=kotlin), User(name=jetbrains)])
961```
962
963<!--- TEST -->
964
965### Array unwrapping
966
967You can also implement the `transformSerialize` function to unwrap a single-element list into a single JSON object
968during serialization:
969
970<!--- INCLUDE
971import kotlinx.serialization.builtins.*
972
973@Serializable
974data class Project(
975    val name: String,
976    @Serializable(with = UserListSerializer::class)
977    val users: List<User>
978)
979
980@Serializable
981data class User(val name: String)
982
983object UserListSerializer : JsonTransformingSerializer<List<User>>(ListSerializer(User.serializer())) {
984-->
985
986```kotlin
987    override fun transformSerialize(element: JsonElement): JsonElement {
988        require(element is JsonArray) // this serializer is used only with lists
989        return element.singleOrNull() ?: element
990    }
991```
992
993<!--- INCLUDE
994}
995-->
996
997Now, if you serialize a single-element list of objects from Kotlin:
998
999```kotlin
1000fun main() {
1001    val data = Project("kotlinx.serialization", listOf(User("kotlin")))
1002    println(Json.encodeToString(data))
1003}
1004```
1005
1006> You can get the full code [here](../guide/example/example-json-24.kt).
1007
1008You end up with a single JSON object, not an array with one element:
1009
1010```text
1011{"name":"kotlinx.serialization","users":{"name":"kotlin"}}
1012```
1013
1014<!--- TEST -->
1015
1016### Manipulating default values
1017
1018Another kind of useful transformation is omitting specific values from the output JSON, for example, if it
1019is used as default when missing or for other reasons.
1020
1021Imagine that you cannot specify a default value for the `language` property in the `Project` data model for some reason,
1022but you need it omitted from the JSON when it is equal to `Kotlin` (we can all agree that Kotlin should be default anyway).
1023You can fix it by writing the special `ProjectSerializer` based on
1024the [Plugin-generated serializer](serializers.md#plugin-generated-serializer) for the `Project` class.
1025
1026```kotlin
1027@Serializable
1028class Project(val name: String, val language: String)
1029
1030object ProjectSerializer : JsonTransformingSerializer<Project>(Project.serializer()) {
1031    override fun transformSerialize(element: JsonElement): JsonElement =
1032        // Filter out top-level key value pair with the key "language" and the value "Kotlin"
1033        JsonObject(element.jsonObject.filterNot {
1034            (k, v) -> k == "language" && v.jsonPrimitive.content == "Kotlin"
1035        })
1036}
1037```
1038
1039In the example below, we are serializing the `Project` class at the top-level, so we explicitly
1040pass the above `ProjectSerializer` to [Json.encodeToString] function as was shown in
1041the [Passing a serializer manually](serializers.md#passing-a-serializer-manually) section:
1042
1043```kotlin
1044fun main() {
1045    val data = Project("kotlinx.serialization", "Kotlin")
1046    println(Json.encodeToString(data)) // using plugin-generated serializer
1047    println(Json.encodeToString(ProjectSerializer, data)) // using custom serializer
1048}
1049```
1050
1051> You can get the full code [here](../guide/example/example-json-25.kt).
1052
1053See the effect of the custom serializer:
1054
1055```text
1056{"name":"kotlinx.serialization","language":"Kotlin"}
1057{"name":"kotlinx.serialization"}
1058```
1059
1060<!--- TEST -->
1061
1062### Content-based polymorphic deserialization
1063
1064Typically, [polymorphic serialization](polymorphism.md) requires a dedicated `"type"` key
1065(also known as _class discriminator_) in the incoming JSON object to determine the actual serializer
1066which should be used to deserialize Kotlin class.
1067
1068However, sometimes the `type` property may not be present in the input. In this case, you need to guess
1069the actual type by the shape of JSON, for example by the presence of a specific key.
1070
1071[JsonContentPolymorphicSerializer] provides a skeleton implementation for such a strategy.
1072To use it, override its `selectDeserializer` method.
1073Let's start with the following class hierarchy.
1074
1075> Note that is does not have to be `sealed` as recommended in the [Sealed classes](polymorphism.md#sealed-classes) section,
1076> because we are not going to take advantage of the plugin-generated code that automatically selects the
1077> appropriate subclass, but are going to implement this code manually.
1078
1079<!--- INCLUDE
1080import kotlinx.serialization.builtins.*
1081-->
1082
1083```kotlin
1084@Serializable
1085abstract class Project {
1086    abstract val name: String
1087}
1088
1089@Serializable
1090data class BasicProject(override val name: String): Project()
1091
1092
1093@Serializable
1094data class OwnedProject(override val name: String, val owner: String) : Project()
1095```
1096
1097You can distinguish the `BasicProject` and `OwnedProject` subclasses by the presence of
1098the `owner` key in the JSON object.
1099
1100```kotlin
1101object ProjectSerializer : JsonContentPolymorphicSerializer<Project>(Project::class) {
1102    override fun selectDeserializer(element: JsonElement) = when {
1103        "owner" in element.jsonObject -> OwnedProject.serializer()
1104        else -> BasicProject.serializer()
1105    }
1106}
1107```
1108
1109When you use this serializer to serialize data, either [registered](polymorphism.md#registered-subclasses) or
1110the default serializer is selected for the actual type at runtime:
1111
1112```kotlin
1113fun main() {
1114    val data = listOf(
1115        OwnedProject("kotlinx.serialization", "kotlin"),
1116        BasicProject("example")
1117    )
1118    val string = Json.encodeToString(ListSerializer(ProjectSerializer), data)
1119    println(string)
1120    println(Json.decodeFromString(ListSerializer(ProjectSerializer), string))
1121}
1122```
1123
1124> You can get the full code [here](../guide/example/example-json-26.kt).
1125
1126No class discriminator is added in the JSON output:
1127
1128```text
1129[{"name":"kotlinx.serialization","owner":"kotlin"},{"name":"example"}]
1130[OwnedProject(name=kotlinx.serialization, owner=kotlin), BasicProject(name=example)]
1131```
1132
1133<!--- TEST -->
1134
1135### Under the hood (experimental)
1136
1137Although abstract serializers mentioned above can cover most of the cases, it is possible to implement similar machinery
1138manually, using only the [KSerializer] class.
1139If tweaking the abstract methods `transformSerialize`/`transformDeserialize`/`selectDeserializer` is not enough,
1140then altering `serialize`/`deserialize` is a way to go.
1141
1142Here are some useful things about custom serializers with [Json]:
1143
1144* [Encoder] can be cast to [JsonEncoder], and [Decoder] to [JsonDecoder], if the current format is [Json].
1145* `JsonDecoder` has the [decodeJsonElement][JsonDecoder.decodeJsonElement] method and `JsonEncoder`
1146  has the [encodeJsonElement][JsonEncoder.encodeJsonElement] method,
1147  which basically retrieve an element from and insert an element to a current position in the stream.
1148* Both [`JsonDecoder`][JsonDecoder.json] and [`JsonEncoder`][JsonEncoder.json] have the `json` property,
1149  which returns [Json] instance with all settings that are currently in use.
1150* [Json] has the [encodeToJsonElement][Json.encodeToJsonElement] and [decodeFromJsonElement][Json.decodeFromJsonElement] methods.
1151
1152Given all that, it is possible to implement two-stage conversion `Decoder -> JsonElement -> value` or
1153`value -> JsonElement -> Encoder`.
1154For example, you can implement a fully custom serializer for the following `Response` class so that its
1155`Ok` subclass is represented directly, but the `Error` subclass is represented by an object with the error message:
1156
1157<!--- INCLUDE
1158import kotlinx.serialization.descriptors.*
1159import kotlinx.serialization.encoding.*
1160-->
1161
1162```kotlin
1163@Serializable(with = ResponseSerializer::class)
1164sealed class Response<out T> {
1165    data class Ok<out T>(val data: T) : Response<T>()
1166    data class Error(val message: String) : Response<Nothing>()
1167}
1168
1169class ResponseSerializer<T>(private val dataSerializer: KSerializer<T>) : KSerializer<Response<T>> {
1170    override val descriptor: SerialDescriptor = buildSerialDescriptor("Response", PolymorphicKind.SEALED) {
1171        element("Ok", dataSerializer.descriptor)
1172        element("Error", buildClassSerialDescriptor("Error") {
1173          element<String>("message")
1174        })
1175    }
1176
1177    override fun deserialize(decoder: Decoder): Response<T> {
1178        // Decoder -> JsonDecoder
1179        require(decoder is JsonDecoder) // this class can be decoded only by Json
1180        // JsonDecoder -> JsonElement
1181        val element = decoder.decodeJsonElement()
1182        // JsonElement -> value
1183        if (element is JsonObject && "error" in element)
1184            return Response.Error(element["error"]!!.jsonPrimitive.content)
1185        return Response.Ok(decoder.json.decodeFromJsonElement(dataSerializer, element))
1186    }
1187
1188    override fun serialize(encoder: Encoder, value: Response<T>) {
1189        // Encoder -> JsonEncoder
1190        require(encoder is JsonEncoder) // This class can be encoded only by Json
1191        // value -> JsonElement
1192        val element = when (value) {
1193            is Response.Ok -> encoder.json.encodeToJsonElement(dataSerializer, value.data)
1194            is Response.Error -> buildJsonObject { put("error", value.message) }
1195        }
1196        // JsonElement -> JsonEncoder
1197        encoder.encodeJsonElement(element)
1198    }
1199}
1200```
1201
1202Having this serializable `Response` implementation, you can take any serializable payload for its data
1203and serialize or deserialize the corresponding responses:
1204
1205```kotlin
1206@Serializable
1207data class Project(val name: String)
1208
1209fun main() {
1210    val responses = listOf(
1211        Response.Ok(Project("kotlinx.serialization")),
1212        Response.Error("Not found")
1213    )
1214    val string = Json.encodeToString(responses)
1215    println(string)
1216    println(Json.decodeFromString<List<Response<Project>>>(string))
1217}
1218```
1219
1220> You can get the full code [here](../guide/example/example-json-27.kt).
1221
1222This gives you fine-grained control on the representation of the `Response` class in the JSON output:
1223
1224```text
1225[{"name":"kotlinx.serialization"},{"error":"Not found"}]
1226[Ok(data=Project(name=kotlinx.serialization)), Error(message=Not found)]
1227```
1228
1229<!--- TEST -->
1230
1231### Maintaining custom JSON attributes
1232
1233A good example of custom JSON-specific serializer would be a deserializer
1234that packs all unknown JSON properties into a dedicated field of `JsonObject` type.
1235
1236Let's add `UnknownProject` &ndash; a class with the `name` property and arbitrary details flattened into the same object:
1237
1238<!--- INCLUDE
1239import kotlinx.serialization.descriptors.*
1240import kotlinx.serialization.encoding.*
1241-->
1242
1243```kotlin
1244data class UnknownProject(val name: String, val details: JsonObject)
1245```
1246
1247However, the default plugin-generated serializer requires details
1248to be a separate JSON object and that's not what we want.
1249
1250To mitigate that, write an own serializer that uses the fact that it works only with the `Json` format:
1251
1252```kotlin
1253object UnknownProjectSerializer : KSerializer<UnknownProject> {
1254    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("UnknownProject") {
1255        element<String>("name")
1256        element<JsonElement>("details")
1257    }
1258
1259    override fun deserialize(decoder: Decoder): UnknownProject {
1260        // Cast to JSON-specific interface
1261        val jsonInput = decoder as? JsonDecoder ?: error("Can be deserialized only by JSON")
1262        // Read the whole content as JSON
1263        val json = jsonInput.decodeJsonElement().jsonObject
1264        // Extract and remove name property
1265        val name = json.getValue("name").jsonPrimitive.content
1266        val details = json.toMutableMap()
1267        details.remove("name")
1268        return UnknownProject(name, JsonObject(details))
1269    }
1270
1271    override fun serialize(encoder: Encoder, value: UnknownProject) {
1272        error("Serialization is not supported")
1273    }
1274}
1275```
1276
1277Now it can be used to read flattened JSON details as `UnknownProject`:
1278
1279```kotlin
1280fun main() {
1281    println(Json.decodeFromString(UnknownProjectSerializer, """{"type":"unknown","name":"example","maintainer":"Unknown","license":"Apache 2.0"}"""))
1282}
1283```
1284
1285> You can get the full code [here](../guide/example/example-json-28.kt).
1286
1287```text
1288UnknownProject(name=example, details={"type":"unknown","maintainer":"Unknown","license":"Apache 2.0"})
1289```
1290
1291<!--- TEST -->
1292
1293---
1294
1295The next chapter covers [Alternative and custom formats (experimental)](formats.md).
1296
1297
1298<!-- references -->
1299[RFC-4627]: https://www.ietf.org/rfc/rfc4627.txt
1300[BigDecimal]: https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html
1301
1302<!-- stdlib references -->
1303[Double]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/
1304[Double.NaN]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/-na-n.html
1305[List]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/
1306[Map]: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/
1307
1308<!--- MODULE /kotlinx-serialization-core -->
1309<!--- INDEX kotlinx-serialization-core/kotlinx.serialization -->
1310
1311[SerialName]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serial-name/index.html
1312[InheritableSerialInfo]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-inheritable-serial-info/index.html
1313[KSerializer]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-k-serializer/index.html
1314[Serializable]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serializable/index.html
1315
1316<!--- INDEX kotlinx-serialization-core/kotlinx.serialization.encoding -->
1317
1318[Encoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/index.html
1319[Decoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/index.html
1320
1321<!--- MODULE /kotlinx-serialization-json -->
1322<!--- INDEX kotlinx-serialization-json/kotlinx.serialization.json -->
1323
1324[Json]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json/index.html
1325[Json()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json.html
1326[JsonBuilder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/index.html
1327[JsonBuilder.prettyPrint]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/pretty-print.html
1328[JsonBuilder.isLenient]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/is-lenient.html
1329[JsonBuilder.ignoreUnknownKeys]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/ignore-unknown-keys.html
1330[JsonNames]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-names/index.html
1331[JsonBuilder.useAlternativeNames]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/use-alternative-names.html
1332[JsonBuilder.coerceInputValues]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/coerce-input-values.html
1333[JsonBuilder.encodeDefaults]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/encode-defaults.html
1334[JsonBuilder.explicitNulls]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/explicit-nulls.html
1335[JsonBuilder.allowStructuredMapKeys]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/allow-structured-map-keys.html
1336[JsonBuilder.allowSpecialFloatingPointValues]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/allow-special-floating-point-values.html
1337[JsonBuilder.classDiscriminator]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/class-discriminator.html
1338[JsonClassDiscriminator]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-class-discriminator/index.html
1339[JsonBuilder.classDiscriminatorMode]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/class-discriminator-mode.html
1340[ClassDiscriminatorMode.NONE]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-class-discriminator-mode/-n-o-n-e/index.html
1341[ClassDiscriminatorMode.POLYMORPHIC]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-class-discriminator-mode/-p-o-l-y-m-o-r-p-h-i-c/index.html
1342[ClassDiscriminatorMode.ALL_JSON_OBJECTS]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-class-discriminator-mode/-a-l-l_-j-s-o-n_-o-b-j-e-c-t-s/index.html
1343[JsonBuilder.decodeEnumsCaseInsensitive]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/decode-enums-case-insensitive.html
1344[JsonBuilder.namingStrategy]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/naming-strategy.html
1345[JsonNamingStrategy]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-naming-strategy/index.html
1346[JsonElement]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-element/index.html
1347[Json.parseToJsonElement]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json/parse-to-json-element.html
1348[JsonPrimitive]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-primitive/index.html
1349[JsonPrimitive.content]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-primitive/content.html
1350[JsonPrimitive()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-primitive.html
1351[JsonArray]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-array/index.html
1352[JsonObject]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-object/index.html
1353[_jsonPrimitive]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/json-primitive.html
1354[_jsonArray]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/json-array.html
1355[_jsonObject]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/json-object.html
1356[int]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/int.html
1357[intOrNull]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/int-or-null.html
1358[long]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/long.html
1359[longOrNull]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/long-or-null.html
1360[buildJsonArray]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/build-json-array.html
1361[buildJsonObject]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/build-json-object.html
1362[Json.decodeFromJsonElement]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/decode-from-json-element.html
1363[JsonUnquotedLiteral]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-unquoted-literal.html
1364[JsonNull]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-null/index.html
1365[JsonTransformingSerializer]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-transforming-serializer/index.html
1366[Json.encodeToString]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json/encode-to-string.html
1367[JsonContentPolymorphicSerializer]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-content-polymorphic-serializer/index.html
1368[JsonEncoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-encoder/index.html
1369[JsonDecoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-decoder/index.html
1370[JsonDecoder.decodeJsonElement]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-decoder/decode-json-element.html
1371[JsonEncoder.encodeJsonElement]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-encoder/encode-json-element.html
1372[JsonDecoder.json]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-decoder/json.html
1373[JsonEncoder.json]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-encoder/json.html
1374[Json.encodeToJsonElement]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/encode-to-json-element.html
1375
1376<!--- END -->
1377