xref: /aosp_15_r20/external/kotlinx.serialization/docs/serializers.md (revision 57b5a4a64c534cf7f27ac9427ceab07f3d8ed3d8)
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&mdash;`r`, `g`, and `b`&mdash;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&mdash;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