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