1<!--- TEST_NAME SerializersTest --> 2 3# Serializers 4 5This is the third chapter of the [Kotlin Serialization Guide](serialization-guide.md). 6In this chapter we'll take a look at serializers in more detail, and we'll see how custom serializers can be written. 7 8**Table of contents** 9 10<!--- TOC --> 11 12* [Introduction to serializers](#introduction-to-serializers) 13 * [Plugin-generated serializer](#plugin-generated-serializer) 14 * [Plugin-generated generic serializer](#plugin-generated-generic-serializer) 15 * [Builtin primitive serializers](#builtin-primitive-serializers) 16 * [Constructing collection serializers](#constructing-collection-serializers) 17 * [Using top-level serializer function](#using-top-level-serializer-function) 18* [Custom serializers](#custom-serializers) 19 * [Primitive serializer](#primitive-serializer) 20 * [Delegating serializers](#delegating-serializers) 21 * [Composite serializer via surrogate](#composite-serializer-via-surrogate) 22 * [Hand-written composite serializer](#hand-written-composite-serializer) 23 * [Sequential decoding protocol (experimental)](#sequential-decoding-protocol-experimental) 24 * [Serializing 3rd party classes](#serializing-3rd-party-classes) 25 * [Passing a serializer manually](#passing-a-serializer-manually) 26 * [Specifying serializer on a property](#specifying-serializer-on-a-property) 27 * [Specifying serializer for a particular type](#specifying-serializer-for-a-particular-type) 28 * [Specifying serializers for a file](#specifying-serializers-for-a-file) 29 * [Specifying serializer globally using typealias](#specifying-serializer-globally-using-typealias) 30 * [Custom serializers for a generic type](#custom-serializers-for-a-generic-type) 31 * [Format-specific serializers](#format-specific-serializers) 32* [Contextual serialization](#contextual-serialization) 33 * [Serializers module](#serializers-module) 34 * [Contextual serialization and generic classes](#contextual-serialization-and-generic-classes) 35* [Deriving external serializer for another Kotlin class (experimental)](#deriving-external-serializer-for-another-kotlin-class-experimental) 36 * [External serialization uses properties](#external-serialization-uses-properties) 37 38<!--- END --> 39 40## Introduction to serializers 41 42Formats, like JSON, control the _encoding_ of an object into specific output bytes, but how the object is decomposed 43into its constituent properties is controlled by a _serializer_. So far we've been using automatically-derived 44serializers by using the [`@Serializable`][Serializable] annotation as explained in 45the [Serializable classes](/docs/basic-serialization.md#serializable-classes) section, or using builtin serializers that were shown in 46the [Builtin classes](/docs/builtin-classes.md) section. 47 48As a motivating example, let us take the following `Color` class with an integer value storing its `rgb` bytes. 49 50<!--- INCLUDE 51import kotlinx.serialization.* 52import kotlinx.serialization.json.* 53--> 54 55```kotlin 56@Serializable 57class Color(val rgb: Int) 58 59fun main() { 60 val green = Color(0x00ff00) 61 println(Json.encodeToString(green)) 62} 63``` 64 65> You can get the full code [here](../guide/example/example-serializer-01.kt). 66 67By default this class serializes its `rgb` property into JSON. 68 69```text 70{"rgb":65280} 71``` 72 73<!--- TEST --> 74 75### Plugin-generated serializer 76 77Every class marked with the `@Serializable` annotation, like the `Color` class from the previous example, 78gets an instance of the [KSerializer] interface automatically generated by the Kotlin Serialization compiler plugin. 79We can retrieve this instance using the `.serializer()` function on the class's companion object. 80 81We can examine its [descriptor][KSerializer.descriptor] property that describes the structure of 82the serialized class. We'll learn more details about that in the upcoming sections. 83 84<!--- INCLUDE 85import kotlinx.serialization.* 86 87@Serializable 88@SerialName("Color") 89class Color(val rgb: Int) 90--> 91 92```kotlin 93fun main() { 94 val colorSerializer: KSerializer<Color> = Color.serializer() 95 println(colorSerializer.descriptor) 96} 97``` 98 99> You can get the full code [here](../guide/example/example-serializer-02.kt). 100 101```text 102Color(rgb: kotlin.Int) 103``` 104 105<!--- TEST --> 106 107This serializer is automatically retrieved and used by the Kotlin Serialization framework when the `Color` class 108is itself serialized, or when it is used as a property of other classes. 109 110> You cannot define your own function `serializer()` on a companion object of a serializable class. 111 112### Plugin-generated generic serializer 113 114For generic classes, like the `Box` class shown in the [Generic classes](basic-serialization.md#generic-classes) section, 115the automatically generated `.serializer()` function accepts as many parameters as there are type parameters in the 116corresponding class. These parameters are of type [KSerializer], so the actual type argument's serializer has 117to be provided when constructing an instance of a serializer for a generic class. 118 119<!--- INCLUDE 120import kotlinx.serialization.* 121 122@Serializable 123@SerialName("Color") 124class Color(val rgb: Int) 125--> 126 127```kotlin 128@Serializable 129@SerialName("Box") 130class Box<T>(val contents: T) 131 132fun main() { 133 val boxedColorSerializer = Box.serializer(Color.serializer()) 134 println(boxedColorSerializer.descriptor) 135} 136``` 137 138> You can get the full code [here](../guide/example/example-serializer-03.kt). 139 140As we can see, a serializer was instantiated to serialize a concrete `Box<Color>`. 141 142```text 143Box(contents: Color) 144``` 145 146<!--- TEST --> 147 148### Builtin primitive serializers 149 150The serializers for the [primitive builtin classes](builtin-classes.md#primitives) can be retrieved 151using `.serializer()` extensions. 152 153<!--- INCLUDE 154import kotlinx.serialization.* 155import kotlinx.serialization.builtins.* 156--> 157 158```kotlin 159fun main() { 160 val intSerializer: KSerializer<Int> = Int.serializer() 161 println(intSerializer.descriptor) 162} 163``` 164 165> You can get the full code [here](../guide/example/example-serializer-04.kt). 166 167<!--- TEST 168PrimitiveDescriptor(kotlin.Int) 169--> 170 171### Constructing collection serializers 172 173[Builtin collection serializers](builtin-classes.md#lists), when needed, must be explicitly constructed 174using the corresponding functions [ListSerializer()], [SetSerializer()], [MapSerializer()], etc. 175These classes are generic, so to instantiate their serializer we must provide the serializers for the 176corresponding number of their type parameters. 177For example, we can produce a serializer for a `List<String>` in the following way. 178 179<!--- INCLUDE 180import kotlinx.serialization.* 181import kotlinx.serialization.builtins.* 182--> 183 184```kotlin 185fun main() { 186 val stringListSerializer: KSerializer<List<String>> = ListSerializer(String.serializer()) 187 println(stringListSerializer.descriptor) 188} 189``` 190 191> You can get the full code [here](../guide/example/example-serializer-05.kt). 192 193<!--- TEST 194kotlin.collections.ArrayList(PrimitiveDescriptor(kotlin.String)) 195--> 196 197### Using top-level serializer function 198 199When in doubt, you can always use the top-level generic `serializer<T>()` 200function to retrieve a serializer for an arbitrary Kotlin type in your source-code. 201 202<!--- INCLUDE 203import kotlinx.serialization.* 204--> 205 206```kotlin 207@Serializable 208@SerialName("Color") 209class Color(val rgb: Int) 210 211fun main() { 212 val stringToColorMapSerializer: KSerializer<Map<String, Color>> = serializer() 213 println(stringToColorMapSerializer.descriptor) 214} 215``` 216 217> You can get the full code [here](../guide/example/example-serializer-06.kt). 218 219<!--- TEST 220kotlin.collections.LinkedHashMap(PrimitiveDescriptor(kotlin.String), Color(rgb: kotlin.Int)) 221--> 222 223## Custom serializers 224 225A plugin-generated serializer is convenient, but it may not produce the JSON we want 226for such a class as `Color`. Let's study alternatives. 227 228### Primitive serializer 229 230We want to serialize the `Color` class as a hex string with the green color represented as `"00ff00"`. 231To achieve this, we write an object that implements the [KSerializer] interface for the `Color` class. 232 233<!--- INCLUDE .*-serializer-.* 234import kotlinx.serialization.* 235import kotlinx.serialization.json.* 236import kotlinx.serialization.encoding.* 237import kotlinx.serialization.descriptors.* 238--> 239 240```kotlin 241object ColorAsStringSerializer : KSerializer<Color> { 242 override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Color", PrimitiveKind.STRING) 243 244 override fun serialize(encoder: Encoder, value: Color) { 245 val string = value.rgb.toString(16).padStart(6, '0') 246 encoder.encodeString(string) 247 } 248 249 override fun deserialize(decoder: Decoder): Color { 250 val string = decoder.decodeString() 251 return Color(string.toInt(16)) 252 } 253} 254``` 255 256Serializer has three required pieces. 257 258* The [serialize][SerializationStrategy.serialize] function implements [SerializationStrategy]. 259 It receives an instance of [Encoder] and a value to serialize. 260 It uses the `encodeXxx` functions of `Encoder` to represent a value as a sequence of primitives. There is an 261 `encodeXxx` for each primitive type supported by serialization. 262 In our example, [encodeString][Encoder.encodeString] is used. 263 264* The [deserialize][DeserializationStrategy.deserialize] function implements [DeserializationStrategy]. 265 It receives an instance of [Decoder] and returns a 266 deserialized value. It uses the `decodeXxx` functions of `Decoder`, which mirror the corresponding functions of `Encoder`. 267 In our example [decodeString][Decoder.decodeString] is used. 268 269* The [descriptor][KSerializer.descriptor] property must faithfully explain what exactly the `encodeXxx` and `decodeXxx` 270 functions do so that a format implementation knows in advance what encoding/decoding methods they call. 271 Some formats might also use it to generate a schema for the serialized data. For primitive serialization, 272 the [PrimitiveSerialDescriptor][PrimitiveSerialDescriptor()] function must be used with a unique name of the 273 type that is being serialized. 274 [PrimitiveKind] describes the specific `encodeXxx`/`decodeXxx` method that is being used in the implementation. 275 276> When the `descriptor` does not correspond to the encoding/decoding methods, then the behavior of the resulting code 277> is unspecified, and may arbitrarily change in future updates. 278 279The next step is to bind a serializer to a class. This is done with the [`@Serializable`][Serializable] annotation by adding 280the [`with`][Serializable.with] property value. 281 282```kotlin 283@Serializable(with = ColorAsStringSerializer::class) 284class Color(val rgb: Int) 285``` 286 287Now we can serialize the `Color` class as we did before. 288 289```kotlin 290fun main() { 291 val green = Color(0x00ff00) 292 println(Json.encodeToString(green)) 293} 294``` 295 296> You can get the full code [here](../guide/example/example-serializer-07.kt). 297 298We get the serial representation as the hex string we wanted. 299 300```text 301"00ff00" 302``` 303 304<!--- TEST --> 305 306Deserialization is also straightforward because we implemented the `deserialize` method. 307 308<!--- INCLUDE 309object ColorAsStringSerializer : KSerializer<Color> { 310 override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Color", PrimitiveKind.STRING) 311 312 override fun serialize(encoder: Encoder, value: Color) { 313 val string = value.rgb.toString(16).padStart(6, '0') 314 encoder.encodeString(string) 315 } 316 317 override fun deserialize(decoder: Decoder): Color { 318 val string = decoder.decodeString() 319 return Color(string.toInt(16)) 320 } 321} 322--> 323 324```kotlin 325@Serializable(with = ColorAsStringSerializer::class) 326class Color(val rgb: Int) 327 328fun main() { 329 val color = Json.decodeFromString<Color>("\"00ff00\"") 330 println(color.rgb) // prints 65280 331} 332``` 333 334> You can get the full code [here](../guide/example/example-serializer-08.kt). 335 336<!--- TEST 33765280 338--> 339 340It also works if we serialize or deserialize a different class with `Color` properties. 341 342<!--- INCLUDE 343object ColorAsStringSerializer : KSerializer<Color> { 344 override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Color", PrimitiveKind.STRING) 345 346 override fun serialize(encoder: Encoder, value: Color) { 347 val string = value.rgb.toString(16).padStart(6, '0') 348 encoder.encodeString(string) 349 } 350 351 override fun deserialize(decoder: Decoder): Color { 352 val string = decoder.decodeString() 353 return Color(string.toInt(16)) 354 } 355} 356--> 357 358```kotlin 359@Serializable(with = ColorAsStringSerializer::class) 360data class Color(val rgb: Int) 361 362@Serializable 363data class Settings(val background: Color, val foreground: Color) 364 365fun main() { 366 val data = Settings(Color(0xffffff), Color(0)) 367 val string = Json.encodeToString(data) 368 println(string) 369 require(Json.decodeFromString<Settings>(string) == data) 370} 371``` 372 373> You can get the full code [here](../guide/example/example-serializer-09.kt). 374 375Both `Color` properties are serialized as strings. 376 377```text 378{"background":"ffffff","foreground":"000000"} 379``` 380 381<!--- TEST --> 382 383### Delegating serializers 384 385In the previous example, we represented the `Color` class as a string. 386String is considered to be a primitive type, therefore we used `PrimitiveClassDescriptor` and specialized `encodeString` method. 387Now let's see what our actions would be if we have to serialize `Color` as another non-primitive type, let's say `IntArray`. 388 389An implementation of [KSerializer] for our original `Color` class is going to perform a conversion between 390`Color` and `IntArray`, but delegate the actual serialization logic to the `IntArraySerializer` 391using [encodeSerializableValue][Encoder.encodeSerializableValue] and 392[decodeSerializableValue][Decoder.decodeSerializableValue]. 393 394```kotlin 395import kotlinx.serialization.builtins.IntArraySerializer 396 397class ColorIntArraySerializer : KSerializer<Color> { 398 private val delegateSerializer = IntArraySerializer() 399 override val descriptor = SerialDescriptor("Color", delegateSerializer.descriptor) 400 401 override fun serialize(encoder: Encoder, value: Color) { 402 val data = intArrayOf( 403 (value.rgb shr 16) and 0xFF, 404 (value.rgb shr 8) and 0xFF, 405 value.rgb and 0xFF 406 ) 407 encoder.encodeSerializableValue(delegateSerializer, data) 408 } 409 410 override fun deserialize(decoder: Decoder): Color { 411 val array = decoder.decodeSerializableValue(delegateSerializer) 412 return Color((array[0] shl 16) or (array[1] shl 8) or array[2]) 413 } 414} 415``` 416 417Note that we can't use default `Color.serializer().descriptor` here because formats that rely 418on the schema may think that we would call `encodeInt` instead of `encodeSerializableValue`. 419Neither we can use `IntArraySerializer().descriptor` directly — otherwise, formats that handle int arrays specially 420can't tell if `value` is really a `IntArray` or a `Color`. Don't worry, this optimization would still kick in 421when serializing actual underlying int array. 422 423> Example of how format can treat arrays specially is shown in the [formats guide](formats.md#format-specific-types). 424 425Now we can use the serializer: 426 427```kotlin 428@Serializable(with = ColorIntArraySerializer::class) 429class Color(val rgb: Int) 430 431fun main() { 432 val green = Color(0x00ff00) 433 println(Json.encodeToString(green)) 434} 435``` 436 437As you can see, such array representation is not very useful in JSON, 438but may save some space when used with a `ByteArray` and a binary format. 439 440> You can get the full code [here](../guide/example/example-serializer-10.kt). 441 442```text 443[0,255,0] 444``` 445 446<!--- TEST --> 447 448 449### Composite serializer via surrogate 450 451Now our challenge is to get `Color` serialized so that it is represented in JSON as if it is a class 452with three properties—`r`, `g`, and `b`—so that JSON encodes it as an object. 453The easiest way to achieve this is to define a _surrogate_ class mimicking the serialized form of `Color` that 454we are going to use for its serialization. We also set the [SerialName] of this surrogate class to `Color`. Then if 455any format uses this name the surrogate looks like it is a `Color` class. 456The surrogate class can be `private`, and can enforce all the constraints on the serial representation 457of the class in its `init` block. 458 459```kotlin 460@Serializable 461@SerialName("Color") 462private class ColorSurrogate(val r: Int, val g: Int, val b: Int) { 463 init { 464 require(r in 0..255 && g in 0..255 && b in 0..255) 465 } 466} 467``` 468 469> An example of where the class name is used is shown in 470> the [Custom subclass serial name](polymorphism.md#custom-subclass-serial-name) section in the chapter on polymorphism. 471 472Now we can use the `ColorSurrogate.serializer()` function to retrieve a plugin-generated serializer for the 473surrogate class. 474 475We can use the same approach as in [delegating serializer](#delegating-serializers), but this time, 476we are fully reusing an automatically 477generated [SerialDescriptor] for the surrogate because it should be indistinguishable from the original. 478 479```kotlin 480object ColorSerializer : KSerializer<Color> { 481 override val descriptor: SerialDescriptor = ColorSurrogate.serializer().descriptor 482 483 override fun serialize(encoder: Encoder, value: Color) { 484 val surrogate = ColorSurrogate((value.rgb shr 16) and 0xff, (value.rgb shr 8) and 0xff, value.rgb and 0xff) 485 encoder.encodeSerializableValue(ColorSurrogate.serializer(), surrogate) 486 } 487 488 override fun deserialize(decoder: Decoder): Color { 489 val surrogate = decoder.decodeSerializableValue(ColorSurrogate.serializer()) 490 return Color((surrogate.r shl 16) or (surrogate.g shl 8) or surrogate.b) 491 } 492} 493``` 494 495We bind the `ColorSerializer` serializer to the `Color` class. 496 497```kotlin 498@Serializable(with = ColorSerializer::class) 499class Color(val rgb: Int) 500``` 501 502Now we can enjoy the result of serialization for the `Color` class. 503 504<!--- INCLUDE 505fun main() { 506 val green = Color(0x00ff00) 507 println(Json.encodeToString(green)) 508} 509--> 510 511> You can get the full code [here](../guide/example/example-serializer-11.kt). 512 513```text 514{"r":0,"g":255,"b":0} 515``` 516 517<!--- TEST --> 518 519### Hand-written composite serializer 520 521There are some cases where a surrogate solution does not fit. Perhaps we want to avoid the performance 522implications of additional allocation, or we want a configurable/dynamic set of properties for the 523resulting serial representation. In these cases we need to manually write a class 524serializer which mimics the behaviour of a generated serializer. 525 526```kotlin 527object ColorAsObjectSerializer : KSerializer<Color> { 528``` 529 530Let's introduce it piece by piece. First, a descriptor is defined using the [buildClassSerialDescriptor] builder. 531The [element][ClassSerialDescriptorBuilder.element] function in the builder DSL automatically fetches serializers 532for the corresponding fields by their type. The order of elements is important. They are indexed starting from zero. 533 534```kotlin 535 override val descriptor: SerialDescriptor = 536 buildClassSerialDescriptor("Color") { 537 element<Int>("r") 538 element<Int>("g") 539 element<Int>("b") 540 } 541``` 542 543> The "element" is a generic term here. What is an element of a descriptor depends on its [SerialKind]. 544> Elements of a class descriptor are its properties, elements of a enum descriptor are its cases, etc. 545 546Then we write the `serialize` function using the [encodeStructure] DSL that provides access to 547the [CompositeEncoder] in its block. The difference between [Encoder] and [CompositeEncoder] is the latter 548has `encodeXxxElement` functions that correspond to the `encodeXxx` functions of the former. They must be called 549in the same order as in the descriptor. 550 551```kotlin 552 override fun serialize(encoder: Encoder, value: Color) = 553 encoder.encodeStructure(descriptor) { 554 encodeIntElement(descriptor, 0, (value.rgb shr 16) and 0xff) 555 encodeIntElement(descriptor, 1, (value.rgb shr 8) and 0xff) 556 encodeIntElement(descriptor, 2, value.rgb and 0xff) 557 } 558``` 559 560The most complex piece of code is the `deserialize` function. It must support formats, like JSON, that 561can decode properties in an arbitrary order. It starts with the call to [decodeStructure] to 562get access to a [CompositeDecoder]. Inside it we write a loop that repeatedly calls 563[decodeElementIndex][CompositeDecoder.decodeElementIndex] to decode the index of the next element, then we decode the corresponding 564element using [decodeIntElement][CompositeDecoder.decodeIntElement] in our example, and finally we terminate the loop when 565`CompositeDecoder.DECODE_DONE` is encountered. 566 567```kotlin 568 override fun deserialize(decoder: Decoder): Color = 569 decoder.decodeStructure(descriptor) { 570 var r = -1 571 var g = -1 572 var b = -1 573 while (true) { 574 when (val index = decodeElementIndex(descriptor)) { 575 0 -> r = decodeIntElement(descriptor, 0) 576 1 -> g = decodeIntElement(descriptor, 1) 577 2 -> b = decodeIntElement(descriptor, 2) 578 CompositeDecoder.DECODE_DONE -> break 579 else -> error("Unexpected index: $index") 580 } 581 } 582 require(r in 0..255 && g in 0..255 && b in 0..255) 583 Color((r shl 16) or (g shl 8) or b) 584 } 585``` 586 587<!--- INCLUDE 588} 589--> 590 591Now we bind the resulting serializer to the `Color` class and test its serialization/deserialization. 592 593```kotlin 594@Serializable(with = ColorAsObjectSerializer::class) 595data class Color(val rgb: Int) 596 597fun main() { 598 val color = Color(0x00ff00) 599 val string = Json.encodeToString(color) 600 println(string) 601 require(Json.decodeFromString<Color>(string) == color) 602} 603``` 604 605> You can get the full code [here](../guide/example/example-serializer-12.kt). 606 607As before, we got the `Color` class represented as a JSON object with three keys: 608 609```text 610{"r":0,"g":255,"b":0} 611``` 612 613<!--- TEST --> 614 615### Sequential decoding protocol (experimental) 616 617The implementation of the `deserialize` function from the previous section works with any format. However, 618some formats either always store all the complex data in order, or only do so sometimes (JSON always stores 619collections in order). With these formats the complex protocol of calling `decodeElementIndex` in the loop is 620not needed, and a faster implementation can be used if the [CompositeDecoder.decodeSequentially] function returns `true`. 621The plugin-generated serializers are actually conceptually similar to the below code. 622 623<!--- INCLUDE 624object ColorAsObjectSerializer : KSerializer<Color> { 625 626 override val descriptor: SerialDescriptor = 627 buildClassSerialDescriptor("Color") { 628 element<Int>("r") 629 element<Int>("g") 630 element<Int>("b") 631 } 632 633 override fun serialize(encoder: Encoder, value: Color) = 634 encoder.encodeStructure(descriptor) { 635 encodeIntElement(descriptor, 0, (value.rgb shr 16) and 0xff) 636 encodeIntElement(descriptor, 1, (value.rgb shr 8) and 0xff) 637 encodeIntElement(descriptor, 2, value.rgb and 0xff) 638 } 639--> 640 641```kotlin 642 override fun deserialize(decoder: Decoder): Color = 643 decoder.decodeStructure(descriptor) { 644 var r = -1 645 var g = -1 646 var b = -1 647 if (decodeSequentially()) { // sequential decoding protocol 648 r = decodeIntElement(descriptor, 0) 649 g = decodeIntElement(descriptor, 1) 650 b = decodeIntElement(descriptor, 2) 651 } else while (true) { 652 when (val index = decodeElementIndex(descriptor)) { 653 0 -> r = decodeIntElement(descriptor, 0) 654 1 -> g = decodeIntElement(descriptor, 1) 655 2 -> b = decodeIntElement(descriptor, 2) 656 CompositeDecoder.DECODE_DONE -> break 657 else -> error("Unexpected index: $index") 658 } 659 } 660 require(r in 0..255 && g in 0..255 && b in 0..255) 661 Color((r shl 16) or (g shl 8) or b) 662 } 663``` 664 665<!--- INCLUDE 666} 667 668@Serializable(with = ColorAsObjectSerializer::class) 669data class Color(val rgb: Int) 670 671fun main() { 672 val color = Color(0x00ff00) 673 val string = Json.encodeToString(color) 674 println(string) 675 require(Json.decodeFromString<Color>(string) == color) 676} 677--> 678 679> You can get the full code [here](../guide/example/example-serializer-13.kt). 680 681<!--- TEST 682{"r":0,"g":255,"b":0} 683--> 684 685### Serializing 3rd party classes 686 687Sometimes an application has to work with an external type that is not serializable. 688Let us use [java.util.Date] as an example. As before, we start by writing an implementation of [KSerializer] 689for the class. Our goal is to get a `Date` serialized as a long number of milliseconds following the 690approach from the [Primitive serializer](#primitive-serializer) section. 691 692> In the following sections any kind of `Date` serializer would work. For example, if we want `Date` to be serialized 693> as an object, we would use an approach from 694> the [Composite serializer via surrogate](#composite-serializer-via-surrogate) section. 695> See also [Deriving external serializer for another Kotlin class (experimental)](#deriving-external-serializer-for-another-kotlin-class-experimental) 696> when you need to serialize a 3rd-party Kotlin class that could have been serializable, but is not. 697 698<!--- INCLUDE 699import java.util.Date 700import java.text.SimpleDateFormat 701--> 702 703```kotlin 704object DateAsLongSerializer : KSerializer<Date> { 705 override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG) 706 override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time) 707 override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong()) 708} 709``` 710 711We cannot bind the `DateAsLongSerializer` serializer to the `Date` class with the [`@Serializable`][Serializable] annotation 712because we don't control the `Date` source code. There are several ways to work around that. 713 714### Passing a serializer manually 715 716All `encodeToXxx` and `decodeFromXxx` functions have an overload with the first serializer parameter. 717When a non-serializable class, like `Date`, is the top-level class being serialized, we can use those. 718 719```kotlin 720fun main() { 721 val kotlin10ReleaseDate = SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00") 722 println(Json.encodeToString(DateAsLongSerializer, kotlin10ReleaseDate)) 723} 724``` 725 726> You can get the full code [here](../guide/example/example-serializer-14.kt). 727 728```text 7291455494400000 730``` 731 732<!--- TEST --> 733 734### Specifying serializer on a property 735 736When a property of a non-serializable class, like `Date`, is serialized as part of a serializable class we must supply 737its serializer or the code will not compile. This is accomplished using the [`@Serializable`][Serializable] annotation on the property. 738 739<!--- INCLUDE 740import java.util.Date 741import java.text.SimpleDateFormat 742 743object DateAsLongSerializer : KSerializer<Date> { 744 override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG) 745 override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time) 746 override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong()) 747} 748--> 749 750```kotlin 751@Serializable 752class ProgrammingLanguage( 753 val name: String, 754 @Serializable(with = DateAsLongSerializer::class) 755 val stableReleaseDate: Date 756) 757 758fun main() { 759 val data = ProgrammingLanguage("Kotlin", SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00")) 760 println(Json.encodeToString(data)) 761} 762``` 763 764> You can get the full code [here](../guide/example/example-serializer-15.kt). 765 766The `stableReleaseDate` property is serialized with the serialization strategy that we specified for it: 767 768```text 769{"name":"Kotlin","stableReleaseDate":1455494400000} 770``` 771 772<!--- TEST --> 773 774### Specifying serializer for a particular type 775 776[`@Serializable`][Serializable] annotation can also be applied directly to the types. 777This is handy when a class that requires a custom serializer, such as `Date`, happens to be a generic type argument. 778The most common use case for that is when you have a list of dates: 779 780<!--- INCLUDE 781import java.util.Date 782import java.text.SimpleDateFormat 783 784object DateAsLongSerializer : KSerializer<Date> { 785 override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG) 786 override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time) 787 override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong()) 788} 789--> 790 791```kotlin 792@Serializable 793class ProgrammingLanguage( 794 val name: String, 795 val releaseDates: List<@Serializable(DateAsLongSerializer::class) Date> 796) 797 798fun main() { 799 val df = SimpleDateFormat("yyyy-MM-ddX") 800 val data = ProgrammingLanguage("Kotlin", listOf(df.parse("2023-07-06+00"), df.parse("2023-04-25+00"), df.parse("2022-12-28+00"))) 801 println(Json.encodeToString(data)) 802} 803``` 804 805> You can get the full code [here](../guide/example/example-serializer-16.kt). 806 807```text 808{"name":"Kotlin","releaseDates":[1688601600000,1682380800000,1672185600000]} 809``` 810 811<!--- TEST --> 812 813### Specifying serializers for a file 814 815A serializer for a specific type, like `Date`, can be specified for a whole source code file with the file-level 816[UseSerializers] annotation at the beginning of the file. 817 818```kotlin 819@file:UseSerializers(DateAsLongSerializer::class) 820``` 821 822<!--- PREFIX --> 823 824<!--- INCLUDE 825import java.util.Date 826import java.text.SimpleDateFormat 827 828object DateAsLongSerializer : KSerializer<Date> { 829 override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG) 830 override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time) 831 override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong()) 832} 833--> 834 835Now a `Date` property can be used in a serializable class without additional annotations. 836 837```kotlin 838@Serializable 839class ProgrammingLanguage(val name: String, val stableReleaseDate: Date) 840 841fun main() { 842 val data = ProgrammingLanguage("Kotlin", SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00")) 843 println(Json.encodeToString(data)) 844} 845``` 846> You can get the full code [here](../guide/example/example-serializer-17.kt). 847 848```text 849{"name":"Kotlin","stableReleaseDate":1455494400000} 850``` 851 852<!--- TEST --> 853 854### Specifying serializer globally using typealias 855 856kotlinx.serialization tends to be the always-explicit framework when it comes to serialization strategies: normally, 857they should be explicitly mentioned in `@Serializable` annotation. Therefore, we do not provide any kind of global serializer 858configuration (except for [context serializer](#contextual-serialization) mentioned later). 859 860However, in projects with a large number of files and classes, it may be too cumbersome to specify `@file:UseSerializers` 861every time, especially for classes like `Date` or `Instant` that have a fixed strategy of serialization across the project. 862For such cases, it is possible to specify serializers using `typealias`es, as they preserve annotations, including serialization-related ones: 863<!--- INCLUDE 864import java.util.Date 865import java.text.SimpleDateFormat 866 867object DateAsLongSerializer : KSerializer<Date> { 868 override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("DateAsLong", PrimitiveKind.LONG) 869 override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time) 870 override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong()) 871} 872 873object DateAsSimpleTextSerializer: KSerializer<Date> { 874 override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("DateAsSimpleText", PrimitiveKind.LONG) 875 private val format = SimpleDateFormat("yyyy-MM-dd") 876 override fun serialize(encoder: Encoder, value: Date) = encoder.encodeString(format.format(value)) 877 override fun deserialize(decoder: Decoder): Date = format.parse(decoder.decodeString()) 878} 879--> 880 881```kotlin 882typealias DateAsLong = @Serializable(DateAsLongSerializer::class) Date 883 884typealias DateAsText = @Serializable(DateAsSimpleTextSerializer::class) Date 885``` 886 887Using these new different types, it is possible to serialize a Date differently without additional annotations: 888 889```kotlin 890@Serializable 891class ProgrammingLanguage(val stableReleaseDate: DateAsText, val lastReleaseTimestamp: DateAsLong) 892 893fun main() { 894 val format = SimpleDateFormat("yyyy-MM-ddX") 895 val data = ProgrammingLanguage(format.parse("2016-02-15+00"), format.parse("2022-07-07+00")) 896 println(Json.encodeToString(data)) 897} 898``` 899 900> You can get the full code [here](../guide/example/example-serializer-18.kt). 901 902```text 903{"stableReleaseDate":"2016-02-15","lastReleaseTimestamp":1657152000000} 904``` 905 906<!--- TEST --> 907 908### Custom serializers for a generic type 909 910Let us take a look at the following example of the generic `Box<T>` class. 911It is marked with `@Serializable(with = BoxSerializer::class)` as we plan to have a custom serialization 912strategy for it. 913 914```kotlin 915@Serializable(with = BoxSerializer::class) 916data class Box<T>(val contents: T) 917``` 918 919An implementation of [KSerializer] for a regular type is written as an `object`, as we saw in this chapter's 920examples for the `Color` type. A generic class serializer is instantiated with serializers 921for its generic parameters. We saw this in the [Plugin-generated generic serializer](#plugin-generated-generic-serializer) section. 922A custom serializer for a generic class must be a `class` with a constructor that accepts as many [KSerializer] 923parameters as the type has generic parameters. Let us write a `Box<T>` serializer that erases itself during 924serialization, delegating everything to the underlying serializer of its `data` property. 925 926```kotlin 927class BoxSerializer<T>(private val dataSerializer: KSerializer<T>) : KSerializer<Box<T>> { 928 override val descriptor: SerialDescriptor = dataSerializer.descriptor 929 override fun serialize(encoder: Encoder, value: Box<T>) = dataSerializer.serialize(encoder, value.contents) 930 override fun deserialize(decoder: Decoder) = Box(dataSerializer.deserialize(decoder)) 931} 932``` 933 934Now we can serialize and deserialize `Box<Project>`. 935 936```kotlin 937@Serializable 938data class Project(val name: String) 939 940fun main() { 941 val box = Box(Project("kotlinx.serialization")) 942 val string = Json.encodeToString(box) 943 println(string) 944 println(Json.decodeFromString<Box<Project>>(string)) 945} 946``` 947 948> You can get the full code [here](../guide/example/example-serializer-19.kt). 949 950The resulting JSON looks like the `Project` class was serialized directly. 951 952```text 953{"name":"kotlinx.serialization"} 954Box(contents=Project(name=kotlinx.serialization)) 955``` 956 957<!--- TEST --> 958 959### Format-specific serializers 960 961The above custom serializers worked in the same way for every format. However, there might be format-specific 962features that a serializer implementation would like to take advantage of. 963 964* The [Json transformations](json.md#json-transformations) section of the [Json](json.md) chapter provides examples 965 of serializers that utilize JSON-specific features. 966 967* A format implementation can have a format-specific representation for a type as explained 968 in the [Format-specific types](formats.md#format-specific-types) section of 969 the [Alternative and custom formats (experimental)](formats.md) chapter. 970 971This chapter proceeds with a generic approach to tweaking the serialization strategy based on the context. 972 973## Contextual serialization 974 975All the previous approaches to specifying custom serialization strategies were _static_, that is 976fully defined at compile-time. The exception was the [Passing a serializer manually](#passing-a-serializer-manually) 977approach, but it worked only on a top-level object. You might need to change the serialization 978strategy for objects deep in the serialized object tree at run-time, with the strategy being selected in a context-dependent way. 979For example, you might want to represent `java.util.Date` in JSON format as an ISO 8601 string or as a long integer 980depending on a version of a protocol you are serializing data for. This is called _contextual_ serialization, and it 981is supported by a built-in [ContextualSerializer] class. Usually we don't have to use this serializer class explicitly—there 982is the [Contextual] annotation providing a shortcut to 983the `@Serializable(with = ContextualSerializer::class)` annotation, 984or the [UseContextualSerialization] annotation can be used at the file-level just like 985the [UseSerializers] annotation. Let's see an example utilizing the former. 986 987<!--- INCLUDE 988import java.util.Date 989import java.text.SimpleDateFormat 990--> 991 992```kotlin 993@Serializable 994class ProgrammingLanguage( 995 val name: String, 996 @Contextual 997 val stableReleaseDate: Date 998) 999``` 1000 1001<!--- INCLUDE 1002 1003fun main() { 1004 val data = ProgrammingLanguage("Kotlin", SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00")) 1005 println(Json.encodeToString(data)) 1006} 1007--> 1008 1009To actually serialize this class we must provide the corresponding context when calling the `encodeToXxx`/`decodeFromXxx` 1010functions. Without it we'll get a "Serializer for class 'Date' is not found" exception. 1011 1012> See [here](../guide/example/example-serializer-20.kt) for an example that produces that exception. 1013 1014<!--- TEST LINES_START 1015Exception in thread "main" kotlinx.serialization.SerializationException: Serializer for class 'Date' is not found. 1016Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied. 1017--> 1018 1019<!--- INCLUDE 1020import kotlinx.serialization.modules.* 1021import java.util.Date 1022import java.text.SimpleDateFormat 1023 1024object DateAsLongSerializer : KSerializer<Date> { 1025 override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG) 1026 override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time) 1027 override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong()) 1028} 1029 1030@Serializable 1031class ProgrammingLanguage( 1032 val name: String, 1033 @Contextual 1034 val stableReleaseDate: Date 1035) 1036--> 1037 1038### Serializers module 1039 1040To provide a context, we define a [SerializersModule] instance that describes which serializers shall be used 1041at run-time to serialize which contextually-serializable classes. This is done using the 1042[SerializersModule {}][SerializersModule()] builder function, which provides the [SerializersModuleBuilder] DSL to 1043register serializers. In the below example we use the [contextual][_contextual] function with the serializer. The corresponding 1044class this serializer is defined for is fetched automatically via the `reified` type parameter. 1045 1046```kotlin 1047private val module = SerializersModule { 1048 contextual(DateAsLongSerializer) 1049} 1050``` 1051 1052Next we create an instance of the [Json] format with this module using the 1053[Json {}][Json()] builder function and the [serializersModule][JsonBuilder.serializersModule] property. 1054 1055> Details on custom JSON configurations can be found in 1056> the [JSON configuration](json.md#json-configuration) section. 1057 1058```kotlin 1059val format = Json { serializersModule = module } 1060``` 1061 1062Now we can serialize our data with this `format`. 1063 1064```kotlin 1065fun main() { 1066 val data = ProgrammingLanguage("Kotlin", SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00")) 1067 println(format.encodeToString(data)) 1068} 1069``` 1070 1071> You can get the full code [here](../guide/example/example-serializer-21.kt). 1072```text 1073{"name":"Kotlin","stableReleaseDate":1455494400000} 1074``` 1075 1076<!--- TEST --> 1077 1078### Contextual serialization and generic classes 1079 1080In the previous section we saw that we can register serializer instance in the module for a class we want to serialize contextually. 1081We also know that [serializers for generic classes have constructor parameters](#custom-serializers-for-a-generic-type) — type arguments serializers. 1082It means that we can't use one serializer instance for a class if this class is generic: 1083 1084```kotlin 1085val incorrectModule = SerializersModule { 1086 // Can serialize only Box<Int>, but not Box<String> or others 1087 contextual(BoxSerializer(Int.serializer())) 1088} 1089``` 1090 1091For cases when one want to serialize contextually a generic class, it is possible to register provider in the module: 1092 1093```kotlin 1094val correctModule = SerializersModule { 1095 // args[0] contains Int.serializer() or String.serializer(), depending on the usage 1096 contextual(Box::class) { args -> BoxSerializer(args[0]) } 1097} 1098``` 1099 1100<!--- CLEAR --> 1101 1102> Additional details on serialization modules are given in 1103> the [Merging library serializers modules](polymorphism.md#merging-library-serializers-modules) section of 1104> the [Polymorphism](polymorphism.md) chapter. 1105 1106## Deriving external serializer for another Kotlin class (experimental) 1107 1108If a 3rd-party class to be serialized is a Kotlin class with a properties-only primary constructor, a kind of 1109class which could have been made `@Serializable`, then you can generate an _external_ serializer for it 1110using the [Serializer] annotation on an object with the [`forClass`][Serializer.forClass] property. 1111 1112```kotlin 1113// NOT @Serializable 1114class Project(val name: String, val language: String) 1115 1116@Serializer(forClass = Project::class) 1117object ProjectSerializer 1118``` 1119 1120You must bind this serializer to a class using one of the approaches explained in this chapter. We'll 1121follow the [Passing a serializer manually](#passing-a-serializer-manually) approach for this example. 1122 1123```kotlin 1124fun main() { 1125 val data = Project("kotlinx.serialization", "Kotlin") 1126 println(Json.encodeToString(ProjectSerializer, data)) 1127} 1128``` 1129 1130> You can get the full code [here](../guide/example/example-serializer-22.kt). 1131 1132This gets all the `Project` properties serialized: 1133 1134```text 1135{"name":"kotlinx.serialization","language":"Kotlin"} 1136``` 1137 1138<!--- TEST --> 1139 1140### External serialization uses properties 1141 1142As we saw earlier, the regular `@Serializable` annotation creates a serializer so that 1143[Backing fields are serialized](basic-serialization.md#backing-fields-are-serialized). _External_ serialization using 1144`Serializer(forClass = ...)` has no access to backing fields and works differently. 1145It serializes only _accessible_ properties that have setters or are part of the primary constructor. 1146The following example shows this. 1147 1148```kotlin 1149// NOT @Serializable, will use external serializer 1150class Project( 1151 // val in a primary constructor -- serialized 1152 val name: String 1153) { 1154 var stars: Int = 0 // property with getter & setter -- serialized 1155 1156 val path: String // getter only -- not serialized 1157 get() = "kotlin/$name" 1158 1159 private var locked: Boolean = false // private, not accessible -- not serialized 1160} 1161 1162@Serializer(forClass = Project::class) 1163object ProjectSerializer 1164 1165fun main() { 1166 val data = Project("kotlinx.serialization").apply { stars = 9000 } 1167 println(Json.encodeToString(ProjectSerializer, data)) 1168} 1169``` 1170 1171> You can get the full code [here](../guide/example/example-serializer-23.kt). 1172 1173The output is shown below. 1174 1175```text 1176{"name":"kotlinx.serialization","stars":9000} 1177``` 1178 1179<!--- TEST --> 1180 1181--- 1182 1183The next chapter covers [Polymorphism](polymorphism.md). 1184 1185<!-- Java references --> 1186[java.util.Date]: https://docs.oracle.com/javase/8/docs/api/java/util/Date.html 1187 1188<!--- MODULE /kotlinx-serialization-core --> 1189<!--- INDEX kotlinx-serialization-core/kotlinx.serialization --> 1190 1191[Serializable]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serializable/index.html 1192[KSerializer]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-k-serializer/index.html 1193[KSerializer.descriptor]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-k-serializer/descriptor.html 1194[SerializationStrategy.serialize]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serialization-strategy/serialize.html 1195[SerializationStrategy]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serialization-strategy/index.html 1196[DeserializationStrategy.deserialize]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-deserialization-strategy/deserialize.html 1197[DeserializationStrategy]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-deserialization-strategy/index.html 1198[Serializable.with]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serializable/with.html 1199[SerialName]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serial-name/index.html 1200[UseSerializers]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-use-serializers/index.html 1201[ContextualSerializer]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-contextual-serializer/index.html 1202[Contextual]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-contextual/index.html 1203[UseContextualSerialization]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-use-contextual-serialization/index.html 1204[Serializer]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serializer/index.html 1205[Serializer.forClass]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serializer/for-class.html 1206 1207<!--- INDEX kotlinx-serialization-core/kotlinx.serialization.builtins --> 1208 1209[ListSerializer()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.builtins/-list-serializer.html 1210[SetSerializer()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.builtins/-set-serializer.html 1211[MapSerializer()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.builtins/-map-serializer.html 1212 1213<!--- INDEX kotlinx-serialization-core/kotlinx.serialization.encoding --> 1214 1215[Encoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/index.html 1216[Encoder.encodeString]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/encode-string.html 1217[Decoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/index.html 1218[Decoder.decodeString]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/decode-string.html 1219[Encoder.encodeSerializableValue]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/encode-serializable-value.html 1220[Decoder.decodeSerializableValue]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/decode-serializable-value.html 1221[encodeStructure]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/encode-structure.html 1222[CompositeEncoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-encoder/index.html 1223[decodeStructure]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/decode-structure.html 1224[CompositeDecoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/index.html 1225[CompositeDecoder.decodeElementIndex]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/decode-element-index.html 1226[CompositeDecoder.decodeIntElement]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/decode-int-element.html 1227[CompositeDecoder.decodeSequentially]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/decode-sequentially.html 1228 1229<!--- INDEX kotlinx-serialization-core/kotlinx.serialization.descriptors --> 1230 1231[PrimitiveSerialDescriptor()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.descriptors/-primitive-serial-descriptor.html 1232[PrimitiveKind]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.descriptors/-primitive-kind/index.html 1233[SerialDescriptor]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.descriptors/-serial-descriptor/index.html 1234[buildClassSerialDescriptor]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.descriptors/build-class-serial-descriptor.html 1235[ClassSerialDescriptorBuilder.element]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.descriptors/element.html 1236[SerialKind]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.descriptors/-serial-kind/index.html 1237 1238<!--- INDEX kotlinx-serialization-core/kotlinx.serialization.modules --> 1239 1240[SerializersModule]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module/index.html 1241[SerializersModule()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module.html 1242[SerializersModuleBuilder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module-builder/index.html 1243[_contextual]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/contextual.html 1244 1245<!--- MODULE /kotlinx-serialization-json --> 1246<!--- INDEX kotlinx-serialization-json/kotlinx.serialization.json --> 1247 1248[Json]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json/index.html 1249[Json()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json.html 1250[JsonBuilder.serializersModule]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/serializers-module.html 1251 1252<!--- END --> 1253 1254