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