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` – 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