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