xref: /aosp_15_r20/external/kotlinx.serialization/docs/formats.md (revision 57b5a4a64c534cf7f27ac9427ceab07f3d8ed3d8)
1*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST_NAME FormatsTest -->
2*57b5a4a6SAndroid Build Coastguard Worker
3*57b5a4a6SAndroid Build Coastguard Worker# Alternative and custom formats (experimental)
4*57b5a4a6SAndroid Build Coastguard Worker
5*57b5a4a6SAndroid Build Coastguard WorkerThis is the sixth chapter of the [Kotlin Serialization Guide](serialization-guide.md).
6*57b5a4a6SAndroid Build Coastguard WorkerIt goes beyond JSON, covering alternative and custom formats. Unlike JSON, which is
7*57b5a4a6SAndroid Build Coastguard Workerstable, these are currently experimental features of Kotlin Serialization.
8*57b5a4a6SAndroid Build Coastguard Worker
9*57b5a4a6SAndroid Build Coastguard Worker**Table of contents**
10*57b5a4a6SAndroid Build Coastguard Worker
11*57b5a4a6SAndroid Build Coastguard Worker<!--- TOC -->
12*57b5a4a6SAndroid Build Coastguard Worker
13*57b5a4a6SAndroid Build Coastguard Worker* [CBOR (experimental)](#cbor-experimental)
14*57b5a4a6SAndroid Build Coastguard Worker  * [Ignoring unknown keys](#ignoring-unknown-keys)
15*57b5a4a6SAndroid Build Coastguard Worker  * [Byte arrays and CBOR data types](#byte-arrays-and-cbor-data-types)
16*57b5a4a6SAndroid Build Coastguard Worker* [ProtoBuf (experimental)](#protobuf-experimental)
17*57b5a4a6SAndroid Build Coastguard Worker  * [Field numbers](#field-numbers)
18*57b5a4a6SAndroid Build Coastguard Worker  * [Integer types](#integer-types)
19*57b5a4a6SAndroid Build Coastguard Worker  * [Lists as repeated fields](#lists-as-repeated-fields)
20*57b5a4a6SAndroid Build Coastguard Worker  * [Packed fields](#packed-fields)
21*57b5a4a6SAndroid Build Coastguard Worker  * [ProtoBuf schema generator (experimental)](#protobuf-schema-generator-experimental)
22*57b5a4a6SAndroid Build Coastguard Worker* [Properties (experimental)](#properties-experimental)
23*57b5a4a6SAndroid Build Coastguard Worker* [Custom formats (experimental)](#custom-formats-experimental)
24*57b5a4a6SAndroid Build Coastguard Worker  * [Basic encoder](#basic-encoder)
25*57b5a4a6SAndroid Build Coastguard Worker  * [Basic decoder](#basic-decoder)
26*57b5a4a6SAndroid Build Coastguard Worker  * [Sequential decoding](#sequential-decoding)
27*57b5a4a6SAndroid Build Coastguard Worker  * [Adding collection support](#adding-collection-support)
28*57b5a4a6SAndroid Build Coastguard Worker  * [Adding null support](#adding-null-support)
29*57b5a4a6SAndroid Build Coastguard Worker  * [Efficient binary format](#efficient-binary-format)
30*57b5a4a6SAndroid Build Coastguard Worker  * [Format-specific types](#format-specific-types)
31*57b5a4a6SAndroid Build Coastguard Worker
32*57b5a4a6SAndroid Build Coastguard Worker<!--- END -->
33*57b5a4a6SAndroid Build Coastguard Worker
34*57b5a4a6SAndroid Build Coastguard Worker## CBOR (experimental)
35*57b5a4a6SAndroid Build Coastguard Worker
36*57b5a4a6SAndroid Build Coastguard Worker[CBOR][RFC 7049] is one of the standard compact binary
37*57b5a4a6SAndroid Build Coastguard Workerencodings for JSON, so it supports a subset of [JSON features](json.md) and
38*57b5a4a6SAndroid Build Coastguard Workeris generally very similar to JSON in use, but produces binary data.
39*57b5a4a6SAndroid Build Coastguard Worker
40*57b5a4a6SAndroid Build Coastguard Worker> CBOR support is (experimentally) available in a separate
41*57b5a4a6SAndroid Build Coastguard Worker> `org.jetbrains.kotlinx:kotlinx-serialization-cbor:<version>` module.
42*57b5a4a6SAndroid Build Coastguard Worker
43*57b5a4a6SAndroid Build Coastguard Worker[Cbor] class has [Cbor.encodeToByteArray] and [Cbor.decodeFromByteArray] functions.
44*57b5a4a6SAndroid Build Coastguard WorkerLet us take the basic example from the [JSON encoding](basic-serialization.md#json-encoding),
45*57b5a4a6SAndroid Build Coastguard Workerbut encode it using CBOR.
46*57b5a4a6SAndroid Build Coastguard Worker
47*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
48*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
49*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.cbor.*
50*57b5a4a6SAndroid Build Coastguard Worker
51*57b5a4a6SAndroid Build Coastguard Workerfun ByteArray.toAsciiHexString() = joinToString("") {
52*57b5a4a6SAndroid Build Coastguard Worker    if (it in 32..127) it.toInt().toChar().toString() else
53*57b5a4a6SAndroid Build Coastguard Worker        "{${it.toUByte().toString(16).padStart(2, '0').uppercase()}}"
54*57b5a4a6SAndroid Build Coastguard Worker}
55*57b5a4a6SAndroid Build Coastguard Worker-->
56*57b5a4a6SAndroid Build Coastguard Worker
57*57b5a4a6SAndroid Build Coastguard Worker```kotlin
58*57b5a4a6SAndroid Build Coastguard Worker@Serializable
59*57b5a4a6SAndroid Build Coastguard Workerdata class Project(val name: String, val language: String)
60*57b5a4a6SAndroid Build Coastguard Worker
61*57b5a4a6SAndroid Build Coastguard Workerfun main() {
62*57b5a4a6SAndroid Build Coastguard Worker    val data = Project("kotlinx.serialization", "Kotlin")
63*57b5a4a6SAndroid Build Coastguard Worker    val bytes = Cbor.encodeToByteArray(data)
64*57b5a4a6SAndroid Build Coastguard Worker    println(bytes.toAsciiHexString())
65*57b5a4a6SAndroid Build Coastguard Worker    val obj = Cbor.decodeFromByteArray<Project>(bytes)
66*57b5a4a6SAndroid Build Coastguard Worker    println(obj)
67*57b5a4a6SAndroid Build Coastguard Worker}
68*57b5a4a6SAndroid Build Coastguard Worker```
69*57b5a4a6SAndroid Build Coastguard Worker
70*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-01.kt).
71*57b5a4a6SAndroid Build Coastguard Worker
72*57b5a4a6SAndroid Build Coastguard WorkerWe print a filtered ASCII representation of the output, writing non-ASCII data in hex, so we see how
73*57b5a4a6SAndroid Build Coastguard Workerall the original strings are directly represented in CBOR, but the format delimiters themselves are binary.
74*57b5a4a6SAndroid Build Coastguard Worker
75*57b5a4a6SAndroid Build Coastguard Worker```text
76*57b5a4a6SAndroid Build Coastguard Worker{BF}dnameukotlinx.serializationhlanguagefKotlin{FF}
77*57b5a4a6SAndroid Build Coastguard WorkerProject(name=kotlinx.serialization, language=Kotlin)
78*57b5a4a6SAndroid Build Coastguard Worker```
79*57b5a4a6SAndroid Build Coastguard Worker
80*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST -->
81*57b5a4a6SAndroid Build Coastguard Worker
82*57b5a4a6SAndroid Build Coastguard WorkerIn [CBOR hex notation](http://cbor.me/), the output is equivalent to the following:
83*57b5a4a6SAndroid Build Coastguard Worker```
84*57b5a4a6SAndroid Build Coastguard WorkerBF                                      # map(*)
85*57b5a4a6SAndroid Build Coastguard Worker   64                                   # text(4)
86*57b5a4a6SAndroid Build Coastguard Worker      6E616D65                          # "name"
87*57b5a4a6SAndroid Build Coastguard Worker   75                                   # text(21)
88*57b5a4a6SAndroid Build Coastguard Worker      6B6F746C696E782E73657269616C697A6174696F6E # "kotlinx.serialization"
89*57b5a4a6SAndroid Build Coastguard Worker   68                                   # text(8)
90*57b5a4a6SAndroid Build Coastguard Worker      6C616E6775616765                  # "language"
91*57b5a4a6SAndroid Build Coastguard Worker   66                                   # text(6)
92*57b5a4a6SAndroid Build Coastguard Worker      4B6F746C696E                      # "Kotlin"
93*57b5a4a6SAndroid Build Coastguard Worker   FF                                   # primitive(*)
94*57b5a4a6SAndroid Build Coastguard Worker```
95*57b5a4a6SAndroid Build Coastguard Worker
96*57b5a4a6SAndroid Build Coastguard Worker> Note, CBOR as a format, unlike JSON, supports maps with non-trivial keys
97*57b5a4a6SAndroid Build Coastguard Worker> (see the [Allowing structured map keys](json.md#allowing-structured-map-keys) section for JSON workarounds),
98*57b5a4a6SAndroid Build Coastguard Worker> and Kotlin maps are serialized as CBOR maps, but some parsers (like `jackson-dataformat-cbor`) don't support this.
99*57b5a4a6SAndroid Build Coastguard Worker
100*57b5a4a6SAndroid Build Coastguard Worker### Ignoring unknown keys
101*57b5a4a6SAndroid Build Coastguard Worker
102*57b5a4a6SAndroid Build Coastguard WorkerCBOR format is often used to communicate with [IoT] devices where new properties could be added as a part of a device's
103*57b5a4a6SAndroid Build Coastguard WorkerAPI evolution. By default, unknown keys encountered during deserialization produce an error.
104*57b5a4a6SAndroid Build Coastguard WorkerThis behavior can be configured with the [ignoreUnknownKeys][CborBuilder.ignoreUnknownKeys] property.
105*57b5a4a6SAndroid Build Coastguard Worker
106*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
107*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
108*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.cbor.*
109*57b5a4a6SAndroid Build Coastguard Worker-->
110*57b5a4a6SAndroid Build Coastguard Worker
111*57b5a4a6SAndroid Build Coastguard Worker```kotlin
112*57b5a4a6SAndroid Build Coastguard Workerval format = Cbor { ignoreUnknownKeys = true }
113*57b5a4a6SAndroid Build Coastguard Worker
114*57b5a4a6SAndroid Build Coastguard Worker@Serializable
115*57b5a4a6SAndroid Build Coastguard Workerdata class Project(val name: String)
116*57b5a4a6SAndroid Build Coastguard Worker
117*57b5a4a6SAndroid Build Coastguard Workerfun main() {
118*57b5a4a6SAndroid Build Coastguard Worker    val data = format.decodeFromHexString<Project>(
119*57b5a4a6SAndroid Build Coastguard Worker        "bf646e616d65756b6f746c696e782e73657269616c697a6174696f6e686c616e6775616765664b6f746c696eff"
120*57b5a4a6SAndroid Build Coastguard Worker    )
121*57b5a4a6SAndroid Build Coastguard Worker    println(data)
122*57b5a4a6SAndroid Build Coastguard Worker}
123*57b5a4a6SAndroid Build Coastguard Worker```
124*57b5a4a6SAndroid Build Coastguard Worker
125*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-02.kt).
126*57b5a4a6SAndroid Build Coastguard Worker
127*57b5a4a6SAndroid Build Coastguard WorkerIt decodes the object, despite the fact that `Project` is missing the `language` property.
128*57b5a4a6SAndroid Build Coastguard Worker
129*57b5a4a6SAndroid Build Coastguard Worker```text
130*57b5a4a6SAndroid Build Coastguard WorkerProject(name=kotlinx.serialization)
131*57b5a4a6SAndroid Build Coastguard Worker```
132*57b5a4a6SAndroid Build Coastguard Worker
133*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST -->
134*57b5a4a6SAndroid Build Coastguard Worker
135*57b5a4a6SAndroid Build Coastguard WorkerIn [CBOR hex notation](http://cbor.me/), the input is equivalent to the following:
136*57b5a4a6SAndroid Build Coastguard Worker```
137*57b5a4a6SAndroid Build Coastguard WorkerBF                                      # map(*)
138*57b5a4a6SAndroid Build Coastguard Worker   64                                   # text(4)
139*57b5a4a6SAndroid Build Coastguard Worker      6E616D65                          # "name"
140*57b5a4a6SAndroid Build Coastguard Worker   75                                   # text(21)
141*57b5a4a6SAndroid Build Coastguard Worker      6B6F746C696E782E73657269616C697A6174696F6E # "kotlinx.serialization"
142*57b5a4a6SAndroid Build Coastguard Worker   68                                   # text(8)
143*57b5a4a6SAndroid Build Coastguard Worker      6C616E6775616765                  # "language"
144*57b5a4a6SAndroid Build Coastguard Worker   66                                   # text(6)
145*57b5a4a6SAndroid Build Coastguard Worker      4B6F746C696E                      # "Kotlin"
146*57b5a4a6SAndroid Build Coastguard Worker   FF                                   # primitive(*)
147*57b5a4a6SAndroid Build Coastguard Worker```
148*57b5a4a6SAndroid Build Coastguard Worker
149*57b5a4a6SAndroid Build Coastguard Worker### Byte arrays and CBOR data types
150*57b5a4a6SAndroid Build Coastguard Worker
151*57b5a4a6SAndroid Build Coastguard WorkerPer the [RFC 7049 Major Types] section, CBOR supports the following data types:
152*57b5a4a6SAndroid Build Coastguard Worker
153*57b5a4a6SAndroid Build Coastguard Worker- Major type 0: an unsigned integer
154*57b5a4a6SAndroid Build Coastguard Worker- Major type 1: a negative integer
155*57b5a4a6SAndroid Build Coastguard Worker- **Major type 2: a byte string**
156*57b5a4a6SAndroid Build Coastguard Worker- Major type 3: a text string
157*57b5a4a6SAndroid Build Coastguard Worker- **Major type 4: an array of data items**
158*57b5a4a6SAndroid Build Coastguard Worker- Major type 5: a map of pairs of data items
159*57b5a4a6SAndroid Build Coastguard Worker- Major type 6: optional semantic tagging of other major types
160*57b5a4a6SAndroid Build Coastguard Worker- Major type 7: floating-point numbers and simple data types that need no content, as well as the "break" stop code
161*57b5a4a6SAndroid Build Coastguard Worker
162*57b5a4a6SAndroid Build Coastguard WorkerBy default, Kotlin `ByteArray` instances are encoded as **major type 4**.
163*57b5a4a6SAndroid Build Coastguard WorkerWhen **major type 2** is desired, then the [`@ByteString`][ByteString] annotation can be used.
164*57b5a4a6SAndroid Build Coastguard Worker
165*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
166*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
167*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.cbor.*
168*57b5a4a6SAndroid Build Coastguard Worker
169*57b5a4a6SAndroid Build Coastguard Workerfun ByteArray.toAsciiHexString() = joinToString("") {
170*57b5a4a6SAndroid Build Coastguard Worker    if (it in 32..127) it.toInt().toChar().toString() else
171*57b5a4a6SAndroid Build Coastguard Worker        "{${it.toUByte().toString(16).padStart(2, '0').uppercase()}}"
172*57b5a4a6SAndroid Build Coastguard Worker}
173*57b5a4a6SAndroid Build Coastguard Worker-->
174*57b5a4a6SAndroid Build Coastguard Worker
175*57b5a4a6SAndroid Build Coastguard Worker```kotlin
176*57b5a4a6SAndroid Build Coastguard Worker@Serializable
177*57b5a4a6SAndroid Build Coastguard Workerdata class Data(
178*57b5a4a6SAndroid Build Coastguard Worker    @ByteString
179*57b5a4a6SAndroid Build Coastguard Worker    val type2: ByteArray, // CBOR Major type 2
180*57b5a4a6SAndroid Build Coastguard Worker    val type4: ByteArray  // CBOR Major type 4
181*57b5a4a6SAndroid Build Coastguard Worker)
182*57b5a4a6SAndroid Build Coastguard Worker
183*57b5a4a6SAndroid Build Coastguard Workerfun main() {
184*57b5a4a6SAndroid Build Coastguard Worker    val data = Data(byteArrayOf(1, 2, 3, 4), byteArrayOf(5, 6, 7, 8))
185*57b5a4a6SAndroid Build Coastguard Worker    val bytes = Cbor.encodeToByteArray(data)
186*57b5a4a6SAndroid Build Coastguard Worker    println(bytes.toAsciiHexString())
187*57b5a4a6SAndroid Build Coastguard Worker    val obj = Cbor.decodeFromByteArray<Data>(bytes)
188*57b5a4a6SAndroid Build Coastguard Worker    println(obj)
189*57b5a4a6SAndroid Build Coastguard Worker}
190*57b5a4a6SAndroid Build Coastguard Worker```
191*57b5a4a6SAndroid Build Coastguard Worker
192*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-03.kt).
193*57b5a4a6SAndroid Build Coastguard Worker
194*57b5a4a6SAndroid Build Coastguard WorkerAs we see, the CBOR byte that precedes the data is different for different types of encoding.
195*57b5a4a6SAndroid Build Coastguard Worker
196*57b5a4a6SAndroid Build Coastguard Worker```text
197*57b5a4a6SAndroid Build Coastguard Worker{BF}etype2D{01}{02}{03}{04}etype4{9F}{05}{06}{07}{08}{FF}{FF}
198*57b5a4a6SAndroid Build Coastguard WorkerData(type2=[1, 2, 3, 4], type4=[5, 6, 7, 8])
199*57b5a4a6SAndroid Build Coastguard Worker```
200*57b5a4a6SAndroid Build Coastguard Worker
201*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST -->
202*57b5a4a6SAndroid Build Coastguard Worker
203*57b5a4a6SAndroid Build Coastguard WorkerIn [CBOR hex notation](http://cbor.me/), the output is equivalent to the following:
204*57b5a4a6SAndroid Build Coastguard Worker```
205*57b5a4a6SAndroid Build Coastguard WorkerBF               # map(*)
206*57b5a4a6SAndroid Build Coastguard Worker   65            # text(5)
207*57b5a4a6SAndroid Build Coastguard Worker      7479706532 # "type2"
208*57b5a4a6SAndroid Build Coastguard Worker   44            # bytes(4)
209*57b5a4a6SAndroid Build Coastguard Worker      01020304   # "\x01\x02\x03\x04"
210*57b5a4a6SAndroid Build Coastguard Worker   65            # text(5)
211*57b5a4a6SAndroid Build Coastguard Worker      7479706534 # "type4"
212*57b5a4a6SAndroid Build Coastguard Worker   9F            # array(*)
213*57b5a4a6SAndroid Build Coastguard Worker      05         # unsigned(5)
214*57b5a4a6SAndroid Build Coastguard Worker      06         # unsigned(6)
215*57b5a4a6SAndroid Build Coastguard Worker      07         # unsigned(7)
216*57b5a4a6SAndroid Build Coastguard Worker      08         # unsigned(8)
217*57b5a4a6SAndroid Build Coastguard Worker      FF         # primitive(*)
218*57b5a4a6SAndroid Build Coastguard Worker   FF            # primitive(*)
219*57b5a4a6SAndroid Build Coastguard Worker```
220*57b5a4a6SAndroid Build Coastguard Worker
221*57b5a4a6SAndroid Build Coastguard Worker## ProtoBuf (experimental)
222*57b5a4a6SAndroid Build Coastguard Worker
223*57b5a4a6SAndroid Build Coastguard Worker[Protocol Buffers](https://developers.google.com/protocol-buffers) is a language-neutral binary format that normally
224*57b5a4a6SAndroid Build Coastguard Workerrelies on a separate ".proto" file that defines the protocol schema. It is more compact than CBOR, because it
225*57b5a4a6SAndroid Build Coastguard Workerassigns integer numbers to fields instead of names.
226*57b5a4a6SAndroid Build Coastguard Worker
227*57b5a4a6SAndroid Build Coastguard Worker> Protocol buffers support is (experimentally) available in a separate
228*57b5a4a6SAndroid Build Coastguard Worker> `org.jetbrains.kotlinx:kotlinx-serialization-protobuf:<version>` module.
229*57b5a4a6SAndroid Build Coastguard Worker
230*57b5a4a6SAndroid Build Coastguard WorkerKotlin Serialization is using proto2 semantics, where all fields are explicitly required or optional.
231*57b5a4a6SAndroid Build Coastguard WorkerFor a basic example we change our example to use the
232*57b5a4a6SAndroid Build Coastguard Worker[ProtoBuf] class with [ProtoBuf.encodeToByteArray] and [ProtoBuf.decodeFromByteArray] functions.
233*57b5a4a6SAndroid Build Coastguard Worker
234*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
235*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
236*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.protobuf.*
237*57b5a4a6SAndroid Build Coastguard Worker
238*57b5a4a6SAndroid Build Coastguard Workerfun ByteArray.toAsciiHexString() = joinToString("") {
239*57b5a4a6SAndroid Build Coastguard Worker    if (it in 32..127) it.toInt().toChar().toString() else
240*57b5a4a6SAndroid Build Coastguard Worker        "{${it.toUByte().toString(16).padStart(2, '0').uppercase()}}"
241*57b5a4a6SAndroid Build Coastguard Worker}
242*57b5a4a6SAndroid Build Coastguard Worker-->
243*57b5a4a6SAndroid Build Coastguard Worker
244*57b5a4a6SAndroid Build Coastguard Worker```kotlin
245*57b5a4a6SAndroid Build Coastguard Worker@Serializable
246*57b5a4a6SAndroid Build Coastguard Workerdata class Project(val name: String, val language: String)
247*57b5a4a6SAndroid Build Coastguard Worker
248*57b5a4a6SAndroid Build Coastguard Workerfun main() {
249*57b5a4a6SAndroid Build Coastguard Worker    val data = Project("kotlinx.serialization", "Kotlin")
250*57b5a4a6SAndroid Build Coastguard Worker    val bytes = ProtoBuf.encodeToByteArray(data)
251*57b5a4a6SAndroid Build Coastguard Worker    println(bytes.toAsciiHexString())
252*57b5a4a6SAndroid Build Coastguard Worker    val obj = ProtoBuf.decodeFromByteArray<Project>(bytes)
253*57b5a4a6SAndroid Build Coastguard Worker    println(obj)
254*57b5a4a6SAndroid Build Coastguard Worker}
255*57b5a4a6SAndroid Build Coastguard Worker```
256*57b5a4a6SAndroid Build Coastguard Worker
257*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-04.kt).
258*57b5a4a6SAndroid Build Coastguard Worker
259*57b5a4a6SAndroid Build Coastguard Worker```text
260*57b5a4a6SAndroid Build Coastguard Worker{0A}{15}kotlinx.serialization{12}{06}Kotlin
261*57b5a4a6SAndroid Build Coastguard WorkerProject(name=kotlinx.serialization, language=Kotlin)
262*57b5a4a6SAndroid Build Coastguard Worker```
263*57b5a4a6SAndroid Build Coastguard Worker
264*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST -->
265*57b5a4a6SAndroid Build Coastguard Worker
266*57b5a4a6SAndroid Build Coastguard WorkerIn [ProtoBuf hex notation](https://protogen.marcgravell.com/decode), the output is equivalent to the following:
267*57b5a4a6SAndroid Build Coastguard Worker```
268*57b5a4a6SAndroid Build Coastguard WorkerField #1: 0A String Length = 21, Hex = 15, UTF8 = "kotlinx.serialization"
269*57b5a4a6SAndroid Build Coastguard WorkerField #2: 12 String Length = 6, Hex = 06, UTF8 = "Kotlin"
270*57b5a4a6SAndroid Build Coastguard Worker```
271*57b5a4a6SAndroid Build Coastguard Worker
272*57b5a4a6SAndroid Build Coastguard Worker### Field numbers
273*57b5a4a6SAndroid Build Coastguard Worker
274*57b5a4a6SAndroid Build Coastguard WorkerBy default, field numbers in the Kotlin Serialization [ProtoBuf] implementation are automatically assigned,
275*57b5a4a6SAndroid Build Coastguard Workerwhich does not provide the ability to define a stable data schema that evolves over time. That is normally achieved by
276*57b5a4a6SAndroid Build Coastguard Workerwriting a separate ".proto" file. However, with Kotlin Serialization we can get this ability without a separate
277*57b5a4a6SAndroid Build Coastguard Workerschema file, instead using the [ProtoNumber] annotation.
278*57b5a4a6SAndroid Build Coastguard Worker
279*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
280*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
281*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.protobuf.*
282*57b5a4a6SAndroid Build Coastguard Worker
283*57b5a4a6SAndroid Build Coastguard Workerfun ByteArray.toAsciiHexString() = joinToString("") {
284*57b5a4a6SAndroid Build Coastguard Worker    if (it in 32..127) it.toInt().toChar().toString() else
285*57b5a4a6SAndroid Build Coastguard Worker        "{${it.toUByte().toString(16).padStart(2, '0').uppercase()}}"
286*57b5a4a6SAndroid Build Coastguard Worker}
287*57b5a4a6SAndroid Build Coastguard Worker-->
288*57b5a4a6SAndroid Build Coastguard Worker
289*57b5a4a6SAndroid Build Coastguard Worker```kotlin
290*57b5a4a6SAndroid Build Coastguard Worker@Serializable
291*57b5a4a6SAndroid Build Coastguard Workerdata class Project(
292*57b5a4a6SAndroid Build Coastguard Worker    @ProtoNumber(1)
293*57b5a4a6SAndroid Build Coastguard Worker    val name: String,
294*57b5a4a6SAndroid Build Coastguard Worker    @ProtoNumber(3)
295*57b5a4a6SAndroid Build Coastguard Worker    val language: String
296*57b5a4a6SAndroid Build Coastguard Worker)
297*57b5a4a6SAndroid Build Coastguard Worker
298*57b5a4a6SAndroid Build Coastguard Workerfun main() {
299*57b5a4a6SAndroid Build Coastguard Worker    val data = Project("kotlinx.serialization", "Kotlin")
300*57b5a4a6SAndroid Build Coastguard Worker    val bytes = ProtoBuf.encodeToByteArray(data)
301*57b5a4a6SAndroid Build Coastguard Worker    println(bytes.toAsciiHexString())
302*57b5a4a6SAndroid Build Coastguard Worker    val obj = ProtoBuf.decodeFromByteArray<Project>(bytes)
303*57b5a4a6SAndroid Build Coastguard Worker    println(obj)
304*57b5a4a6SAndroid Build Coastguard Worker}
305*57b5a4a6SAndroid Build Coastguard Worker```
306*57b5a4a6SAndroid Build Coastguard Worker
307*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-05.kt).
308*57b5a4a6SAndroid Build Coastguard Worker
309*57b5a4a6SAndroid Build Coastguard WorkerWe see in the output that the number for the first property `name` did not change (as it is numbered from one by default),
310*57b5a4a6SAndroid Build Coastguard Workerbut it did change for the `language` property.
311*57b5a4a6SAndroid Build Coastguard Worker
312*57b5a4a6SAndroid Build Coastguard Worker```text
313*57b5a4a6SAndroid Build Coastguard Worker{0A}{15}kotlinx.serialization{1A}{06}Kotlin
314*57b5a4a6SAndroid Build Coastguard WorkerProject(name=kotlinx.serialization, language=Kotlin)
315*57b5a4a6SAndroid Build Coastguard Worker```
316*57b5a4a6SAndroid Build Coastguard Worker
317*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST -->
318*57b5a4a6SAndroid Build Coastguard Worker
319*57b5a4a6SAndroid Build Coastguard WorkerIn [ProtoBuf hex notation](https://protogen.marcgravell.com/decode), the output is equivalent to the following:
320*57b5a4a6SAndroid Build Coastguard Worker```
321*57b5a4a6SAndroid Build Coastguard WorkerField #1: 0A String Length = 21, Hex = 15, UTF8 = "kotlinx.serialization" (total 21 chars)
322*57b5a4a6SAndroid Build Coastguard WorkerField #3: 1A String Length = 6, Hex = 06, UTF8 = "Kotlin"
323*57b5a4a6SAndroid Build Coastguard Worker```
324*57b5a4a6SAndroid Build Coastguard Worker
325*57b5a4a6SAndroid Build Coastguard Worker### Integer types
326*57b5a4a6SAndroid Build Coastguard Worker
327*57b5a4a6SAndroid Build Coastguard WorkerProtocol buffers support various integer encodings optimized for different ranges of integers.
328*57b5a4a6SAndroid Build Coastguard WorkerThey are specified using the [ProtoType] annotation and the [ProtoIntegerType] enum.
329*57b5a4a6SAndroid Build Coastguard WorkerThe following example shows all three supported options.
330*57b5a4a6SAndroid Build Coastguard Worker
331*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
332*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
333*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.protobuf.*
334*57b5a4a6SAndroid Build Coastguard Worker
335*57b5a4a6SAndroid Build Coastguard Workerfun ByteArray.toAsciiHexString() = joinToString("") {
336*57b5a4a6SAndroid Build Coastguard Worker    if (it in 32..127) it.toInt().toChar().toString() else
337*57b5a4a6SAndroid Build Coastguard Worker        "{${it.toUByte().toString(16).padStart(2, '0').uppercase()}}"
338*57b5a4a6SAndroid Build Coastguard Worker}
339*57b5a4a6SAndroid Build Coastguard Worker-->
340*57b5a4a6SAndroid Build Coastguard Worker
341*57b5a4a6SAndroid Build Coastguard Worker```kotlin
342*57b5a4a6SAndroid Build Coastguard Worker@Serializable
343*57b5a4a6SAndroid Build Coastguard Workerclass Data(
344*57b5a4a6SAndroid Build Coastguard Worker    @ProtoType(ProtoIntegerType.DEFAULT)
345*57b5a4a6SAndroid Build Coastguard Worker    val a: Int,
346*57b5a4a6SAndroid Build Coastguard Worker    @ProtoType(ProtoIntegerType.SIGNED)
347*57b5a4a6SAndroid Build Coastguard Worker    val b: Int,
348*57b5a4a6SAndroid Build Coastguard Worker    @ProtoType(ProtoIntegerType.FIXED)
349*57b5a4a6SAndroid Build Coastguard Worker    val c: Int
350*57b5a4a6SAndroid Build Coastguard Worker)
351*57b5a4a6SAndroid Build Coastguard Worker
352*57b5a4a6SAndroid Build Coastguard Workerfun main() {
353*57b5a4a6SAndroid Build Coastguard Worker    val data = Data(1, -2, 3)
354*57b5a4a6SAndroid Build Coastguard Worker    println(ProtoBuf.encodeToByteArray(data).toAsciiHexString())
355*57b5a4a6SAndroid Build Coastguard Worker}
356*57b5a4a6SAndroid Build Coastguard Worker```
357*57b5a4a6SAndroid Build Coastguard Worker
358*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-06.kt).
359*57b5a4a6SAndroid Build Coastguard Worker
360*57b5a4a6SAndroid Build Coastguard Worker* The [default][ProtoIntegerType.DEFAULT] is a varint encoding (`intXX`) that is optimized for
361*57b5a4a6SAndroid Build Coastguard Worker  small non-negative numbers. The value of `1` is encoded in one byte `01`.
362*57b5a4a6SAndroid Build Coastguard Worker* The [signed][ProtoIntegerType.SIGNED] is a signed ZigZag encoding (`sintXX`) that is optimized for
363*57b5a4a6SAndroid Build Coastguard Worker  small signed integers. The value of `-2` is encoded in one byte `03`.
364*57b5a4a6SAndroid Build Coastguard Worker* The [fixed][ProtoIntegerType.FIXED] encoding (`fixedXX`) always uses a fixed number of bytes.
365*57b5a4a6SAndroid Build Coastguard Worker  The value of `3` is encoded as four bytes `03 00 00 00`.
366*57b5a4a6SAndroid Build Coastguard Worker
367*57b5a4a6SAndroid Build Coastguard Worker> `uintXX` and `sfixedXX` protocol buffer types are not supported.
368*57b5a4a6SAndroid Build Coastguard Worker
369*57b5a4a6SAndroid Build Coastguard Worker```text
370*57b5a4a6SAndroid Build Coastguard Worker{08}{01}{10}{03}{1D}{03}{00}{00}{00}
371*57b5a4a6SAndroid Build Coastguard Worker```
372*57b5a4a6SAndroid Build Coastguard Worker
373*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST -->
374*57b5a4a6SAndroid Build Coastguard Worker
375*57b5a4a6SAndroid Build Coastguard WorkerIn [ProtoBuf hex notation](https://protogen.marcgravell.com/decode) the output is equivalent to the following:
376*57b5a4a6SAndroid Build Coastguard Worker```
377*57b5a4a6SAndroid Build Coastguard WorkerField #1: 08 Varint Value = 1, Hex = 01
378*57b5a4a6SAndroid Build Coastguard WorkerField #2: 10 Varint Value = 3, Hex = 03
379*57b5a4a6SAndroid Build Coastguard WorkerField #3: 1D Fixed32 Value = 3, Hex = 03-00-00-00
380*57b5a4a6SAndroid Build Coastguard Worker```
381*57b5a4a6SAndroid Build Coastguard Worker
382*57b5a4a6SAndroid Build Coastguard Worker### Lists as repeated fields
383*57b5a4a6SAndroid Build Coastguard Worker
384*57b5a4a6SAndroid Build Coastguard WorkerBy default, kotlin lists and other collections are representend as repeated fields.
385*57b5a4a6SAndroid Build Coastguard WorkerIn the protocol buffers when the list is empty there are no elements in the
386*57b5a4a6SAndroid Build Coastguard Workerstream with the corresponding number. For Kotlin Serialization you must explicitly specify a default of `emptyList()`
387*57b5a4a6SAndroid Build Coastguard Workerfor any property of a collection or map type. Otherwise you will not be able deserialize an empty
388*57b5a4a6SAndroid Build Coastguard Workerlist, which is indistinguishable in protocol buffers from a missing field.
389*57b5a4a6SAndroid Build Coastguard Worker
390*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
391*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
392*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.protobuf.*
393*57b5a4a6SAndroid Build Coastguard Worker
394*57b5a4a6SAndroid Build Coastguard Workerfun ByteArray.toAsciiHexString() = joinToString("") {
395*57b5a4a6SAndroid Build Coastguard Worker    if (it in 32..127) it.toInt().toChar().toString() else
396*57b5a4a6SAndroid Build Coastguard Worker        "{${it.toUByte().toString(16).padStart(2, '0').uppercase()}}"
397*57b5a4a6SAndroid Build Coastguard Worker}
398*57b5a4a6SAndroid Build Coastguard Worker-->
399*57b5a4a6SAndroid Build Coastguard Worker
400*57b5a4a6SAndroid Build Coastguard Worker```kotlin
401*57b5a4a6SAndroid Build Coastguard Worker@Serializable
402*57b5a4a6SAndroid Build Coastguard Workerdata class Data(
403*57b5a4a6SAndroid Build Coastguard Worker    val a: List<Int> = emptyList(),
404*57b5a4a6SAndroid Build Coastguard Worker    val b: List<Int> = emptyList()
405*57b5a4a6SAndroid Build Coastguard Worker)
406*57b5a4a6SAndroid Build Coastguard Worker
407*57b5a4a6SAndroid Build Coastguard Workerfun main() {
408*57b5a4a6SAndroid Build Coastguard Worker    val data = Data(listOf(1, 2, 3), listOf())
409*57b5a4a6SAndroid Build Coastguard Worker    val bytes = ProtoBuf.encodeToByteArray(data)
410*57b5a4a6SAndroid Build Coastguard Worker    println(bytes.toAsciiHexString())
411*57b5a4a6SAndroid Build Coastguard Worker    println(ProtoBuf.decodeFromByteArray<Data>(bytes))
412*57b5a4a6SAndroid Build Coastguard Worker}
413*57b5a4a6SAndroid Build Coastguard Worker```
414*57b5a4a6SAndroid Build Coastguard Worker
415*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-07.kt).
416*57b5a4a6SAndroid Build Coastguard Worker
417*57b5a4a6SAndroid Build Coastguard Worker```text
418*57b5a4a6SAndroid Build Coastguard Worker{08}{01}{08}{02}{08}{03}
419*57b5a4a6SAndroid Build Coastguard WorkerData(a=[1, 2, 3], b=[])
420*57b5a4a6SAndroid Build Coastguard Worker```
421*57b5a4a6SAndroid Build Coastguard Worker
422*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST -->
423*57b5a4a6SAndroid Build Coastguard Worker
424*57b5a4a6SAndroid Build Coastguard WorkerIn [ProtoBuf diagnostic mode](https://protogen.marcgravell.com/decode) the output is equivalent to the following:
425*57b5a4a6SAndroid Build Coastguard Worker```
426*57b5a4a6SAndroid Build Coastguard WorkerField #1: 08 Varint Value = 1, Hex = 01
427*57b5a4a6SAndroid Build Coastguard WorkerField #1: 08 Varint Value = 2, Hex = 02
428*57b5a4a6SAndroid Build Coastguard WorkerField #1: 08 Varint Value = 3, Hex = 03
429*57b5a4a6SAndroid Build Coastguard Worker```
430*57b5a4a6SAndroid Build Coastguard Worker
431*57b5a4a6SAndroid Build Coastguard Worker### Packed fields
432*57b5a4a6SAndroid Build Coastguard WorkerCollection types (not maps) can be **written** as packed fields when annotated with the `@ProtoPacked` annotation.
433*57b5a4a6SAndroid Build Coastguard WorkerPer the standard packed fields can only be used on primitive numeric types. The annotation is ignored on other types.
434*57b5a4a6SAndroid Build Coastguard Worker
435*57b5a4a6SAndroid Build Coastguard WorkerPer the [format description](https://developers.google.com/protocol-buffers/docs/encoding#packed) the parser ignores
436*57b5a4a6SAndroid Build Coastguard Workerthe annotation, but rather reads list in either packed or repeated format.
437*57b5a4a6SAndroid Build Coastguard Worker
438*57b5a4a6SAndroid Build Coastguard Worker### ProtoBuf schema generator (experimental)
439*57b5a4a6SAndroid Build Coastguard Worker
440*57b5a4a6SAndroid Build Coastguard WorkerAs mentioned above, when working with protocol buffers you usually use a ".proto" file and a code generator for your
441*57b5a4a6SAndroid Build Coastguard Workerlanguage.  This includes the code to serialize your message to an output stream and deserialize it from an input stream.
442*57b5a4a6SAndroid Build Coastguard WorkerWhen using Kotlin Serialization this step is not necessary because your `@Serializable` Kotlin data types are used as the
443*57b5a4a6SAndroid Build Coastguard Workersource for the schema.
444*57b5a4a6SAndroid Build Coastguard Worker
445*57b5a4a6SAndroid Build Coastguard WorkerThis is very convenient for Kotlin-to-Kotlin communication, but makes interoperability between languages complicated.
446*57b5a4a6SAndroid Build Coastguard WorkerFortunately, you can use the ProtoBuf schema generator to output the ".proto" representation of your messages.  You can
447*57b5a4a6SAndroid Build Coastguard Workerkeep your Kotlin classes as a source of truth and use traditional protoc compilers for other languages at the same time.
448*57b5a4a6SAndroid Build Coastguard Worker
449*57b5a4a6SAndroid Build Coastguard WorkerAs an example, we can display the following data class's ".proto" schema as follows.
450*57b5a4a6SAndroid Build Coastguard Worker
451*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
452*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
453*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.protobuf.*
454*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.protobuf.schema.ProtoBufSchemaGenerator
455*57b5a4a6SAndroid Build Coastguard Worker-->
456*57b5a4a6SAndroid Build Coastguard Worker
457*57b5a4a6SAndroid Build Coastguard Worker```kotlin
458*57b5a4a6SAndroid Build Coastguard Worker@Serializable
459*57b5a4a6SAndroid Build Coastguard Workerdata class SampleData(
460*57b5a4a6SAndroid Build Coastguard Worker    val amount: Long,
461*57b5a4a6SAndroid Build Coastguard Worker    val description: String?,
462*57b5a4a6SAndroid Build Coastguard Worker    val department: String = "QA"
463*57b5a4a6SAndroid Build Coastguard Worker)
464*57b5a4a6SAndroid Build Coastguard Workerfun main() {
465*57b5a4a6SAndroid Build Coastguard Worker  val descriptors = listOf(SampleData.serializer().descriptor)
466*57b5a4a6SAndroid Build Coastguard Worker  val schemas = ProtoBufSchemaGenerator.generateSchemaText(descriptors)
467*57b5a4a6SAndroid Build Coastguard Worker  println(schemas)
468*57b5a4a6SAndroid Build Coastguard Worker}
469*57b5a4a6SAndroid Build Coastguard Worker```
470*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-08.kt).
471*57b5a4a6SAndroid Build Coastguard Worker
472*57b5a4a6SAndroid Build Coastguard WorkerWhich would output as follows.
473*57b5a4a6SAndroid Build Coastguard Worker
474*57b5a4a6SAndroid Build Coastguard Worker```text
475*57b5a4a6SAndroid Build Coastguard Workersyntax = "proto2";
476*57b5a4a6SAndroid Build Coastguard Worker
477*57b5a4a6SAndroid Build Coastguard Worker
478*57b5a4a6SAndroid Build Coastguard Worker// serial name 'example.exampleFormats08.SampleData'
479*57b5a4a6SAndroid Build Coastguard Workermessage SampleData {
480*57b5a4a6SAndroid Build Coastguard Worker  required int64 amount = 1;
481*57b5a4a6SAndroid Build Coastguard Worker  optional string description = 2;
482*57b5a4a6SAndroid Build Coastguard Worker  // WARNING: a default value decoded when value is missing
483*57b5a4a6SAndroid Build Coastguard Worker  optional string department = 3;
484*57b5a4a6SAndroid Build Coastguard Worker}
485*57b5a4a6SAndroid Build Coastguard Worker
486*57b5a4a6SAndroid Build Coastguard Worker```
487*57b5a4a6SAndroid Build Coastguard Worker
488*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST -->
489*57b5a4a6SAndroid Build Coastguard Worker
490*57b5a4a6SAndroid Build Coastguard WorkerNote that since default values are not represented in ".proto" files, a warning is generated when one appears in the schema.
491*57b5a4a6SAndroid Build Coastguard Worker
492*57b5a4a6SAndroid Build Coastguard WorkerSee the documentation for [ProtoBufSchemaGenerator] for more information.
493*57b5a4a6SAndroid Build Coastguard Worker
494*57b5a4a6SAndroid Build Coastguard Worker## Properties (experimental)
495*57b5a4a6SAndroid Build Coastguard Worker
496*57b5a4a6SAndroid Build Coastguard WorkerKotlin Serialization can serialize a class into a flat map with `String` keys via
497*57b5a4a6SAndroid Build Coastguard Workerthe [Properties][kotlinx.serialization.properties.Properties] format implementation.
498*57b5a4a6SAndroid Build Coastguard Worker
499*57b5a4a6SAndroid Build Coastguard Worker> Properties support is (experimentally) available in a separate
500*57b5a4a6SAndroid Build Coastguard Worker> `org.jetbrains.kotlinx:kotlinx-serialization-properties:<version>` module.
501*57b5a4a6SAndroid Build Coastguard Worker
502*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
503*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
504*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.properties.Properties // todo: remove when no longer needed
505*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.properties.*
506*57b5a4a6SAndroid Build Coastguard Worker-->
507*57b5a4a6SAndroid Build Coastguard Worker
508*57b5a4a6SAndroid Build Coastguard Worker```kotlin
509*57b5a4a6SAndroid Build Coastguard Worker@Serializable
510*57b5a4a6SAndroid Build Coastguard Workerclass Project(val name: String, val owner: User)
511*57b5a4a6SAndroid Build Coastguard Worker
512*57b5a4a6SAndroid Build Coastguard Worker@Serializable
513*57b5a4a6SAndroid Build Coastguard Workerclass User(val name: String)
514*57b5a4a6SAndroid Build Coastguard Worker
515*57b5a4a6SAndroid Build Coastguard Workerfun main() {
516*57b5a4a6SAndroid Build Coastguard Worker    val data = Project("kotlinx.serialization",  User("kotlin"))
517*57b5a4a6SAndroid Build Coastguard Worker    val map = Properties.encodeToMap(data)
518*57b5a4a6SAndroid Build Coastguard Worker    map.forEach { (k, v) -> println("$k = $v") }
519*57b5a4a6SAndroid Build Coastguard Worker}
520*57b5a4a6SAndroid Build Coastguard Worker```
521*57b5a4a6SAndroid Build Coastguard Worker
522*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-09.kt).
523*57b5a4a6SAndroid Build Coastguard Worker
524*57b5a4a6SAndroid Build Coastguard WorkerThe resulting map has dot-separated keys representing keys of the nested objects.
525*57b5a4a6SAndroid Build Coastguard Worker
526*57b5a4a6SAndroid Build Coastguard Worker```text
527*57b5a4a6SAndroid Build Coastguard Workername = kotlinx.serialization
528*57b5a4a6SAndroid Build Coastguard Workerowner.name = kotlin
529*57b5a4a6SAndroid Build Coastguard Worker```
530*57b5a4a6SAndroid Build Coastguard Worker
531*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST -->
532*57b5a4a6SAndroid Build Coastguard Worker
533*57b5a4a6SAndroid Build Coastguard Worker## Custom formats (experimental)
534*57b5a4a6SAndroid Build Coastguard Worker
535*57b5a4a6SAndroid Build Coastguard WorkerA custom format for Kotlin Serialization must provide an implementation for the [Encoder] and [Decoder] interfaces that
536*57b5a4a6SAndroid Build Coastguard Workerwe saw used in the [Serializers](serializers.md) chapter.
537*57b5a4a6SAndroid Build Coastguard WorkerThese are pretty large interfaces. For convenience
538*57b5a4a6SAndroid Build Coastguard Workerthe [AbstractEncoder] and [AbstractDecoder] skeleton implementations are provided to simplify the task.
539*57b5a4a6SAndroid Build Coastguard WorkerIn [AbstractEncoder] most of the `encodeXxx` methods have a default implementation that
540*57b5a4a6SAndroid Build Coastguard Workerdelegates to [`encodeValue(value: Any)`][AbstractEncoder.encodeValue] &mdash; the only method that must be
541*57b5a4a6SAndroid Build Coastguard Workerimplemented to get a basic working format.
542*57b5a4a6SAndroid Build Coastguard Worker
543*57b5a4a6SAndroid Build Coastguard Worker### Basic encoder
544*57b5a4a6SAndroid Build Coastguard Worker
545*57b5a4a6SAndroid Build Coastguard WorkerLet us start with a trivial format implementation that encodes the data into a single list of primitive
546*57b5a4a6SAndroid Build Coastguard Workerconstituent objects in the order they were written in the source code. To start, we implement a simple [Encoder] by
547*57b5a4a6SAndroid Build Coastguard Workeroverriding `encodeValue` in [AbstractEncoder].
548*57b5a4a6SAndroid Build Coastguard Worker
549*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
550*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
551*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.descriptors.*
552*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.encoding.*
553*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.*
554*57b5a4a6SAndroid Build Coastguard Worker-->
555*57b5a4a6SAndroid Build Coastguard Worker
556*57b5a4a6SAndroid Build Coastguard Worker```kotlin
557*57b5a4a6SAndroid Build Coastguard Workerclass ListEncoder : AbstractEncoder() {
558*57b5a4a6SAndroid Build Coastguard Worker    val list = mutableListOf<Any>()
559*57b5a4a6SAndroid Build Coastguard Worker
560*57b5a4a6SAndroid Build Coastguard Worker    override val serializersModule: SerializersModule = EmptySerializersModule()
561*57b5a4a6SAndroid Build Coastguard Worker
562*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeValue(value: Any) {
563*57b5a4a6SAndroid Build Coastguard Worker        list.add(value)
564*57b5a4a6SAndroid Build Coastguard Worker    }
565*57b5a4a6SAndroid Build Coastguard Worker}
566*57b5a4a6SAndroid Build Coastguard Worker```
567*57b5a4a6SAndroid Build Coastguard Worker
568*57b5a4a6SAndroid Build Coastguard WorkerNow we write a convenience top-level function that creates an encoder that encodes an object
569*57b5a4a6SAndroid Build Coastguard Workerand returns a list.
570*57b5a4a6SAndroid Build Coastguard Worker
571*57b5a4a6SAndroid Build Coastguard Worker```kotlin
572*57b5a4a6SAndroid Build Coastguard Workerfun <T> encodeToList(serializer: SerializationStrategy<T>, value: T): List<Any> {
573*57b5a4a6SAndroid Build Coastguard Worker    val encoder = ListEncoder()
574*57b5a4a6SAndroid Build Coastguard Worker    encoder.encodeSerializableValue(serializer, value)
575*57b5a4a6SAndroid Build Coastguard Worker    return encoder.list
576*57b5a4a6SAndroid Build Coastguard Worker}
577*57b5a4a6SAndroid Build Coastguard Worker```
578*57b5a4a6SAndroid Build Coastguard Worker
579*57b5a4a6SAndroid Build Coastguard WorkerFor even more convenience, to avoid the need to explicitly pass a serializer, we write an `inline` overload of
580*57b5a4a6SAndroid Build Coastguard Workerthe `encodeToList` function with a `reified` type parameter using the [serializer] function to retrieve
581*57b5a4a6SAndroid Build Coastguard Workerthe appropriate [KSerializer] instance for the actual type.
582*57b5a4a6SAndroid Build Coastguard Worker
583*57b5a4a6SAndroid Build Coastguard Worker```kotlin
584*57b5a4a6SAndroid Build Coastguard Workerinline fun <reified T> encodeToList(value: T) = encodeToList(serializer(), value)
585*57b5a4a6SAndroid Build Coastguard Worker```
586*57b5a4a6SAndroid Build Coastguard Worker
587*57b5a4a6SAndroid Build Coastguard WorkerNow we can test it.
588*57b5a4a6SAndroid Build Coastguard Worker
589*57b5a4a6SAndroid Build Coastguard Worker```kotlin
590*57b5a4a6SAndroid Build Coastguard Worker@Serializable
591*57b5a4a6SAndroid Build Coastguard Workerdata class Project(val name: String, val owner: User, val votes: Int)
592*57b5a4a6SAndroid Build Coastguard Worker
593*57b5a4a6SAndroid Build Coastguard Worker@Serializable
594*57b5a4a6SAndroid Build Coastguard Workerdata class User(val name: String)
595*57b5a4a6SAndroid Build Coastguard Worker
596*57b5a4a6SAndroid Build Coastguard Workerfun main() {
597*57b5a4a6SAndroid Build Coastguard Worker    val data = Project("kotlinx.serialization",  User("kotlin"), 9000)
598*57b5a4a6SAndroid Build Coastguard Worker    println(encodeToList(data))
599*57b5a4a6SAndroid Build Coastguard Worker}
600*57b5a4a6SAndroid Build Coastguard Worker```
601*57b5a4a6SAndroid Build Coastguard Worker
602*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-10.kt).
603*57b5a4a6SAndroid Build Coastguard Worker
604*57b5a4a6SAndroid Build Coastguard WorkerAs a result, we got all the primitive values in our object graph visited and put into a list
605*57b5a4a6SAndroid Build Coastguard Workerin _serial_ order.
606*57b5a4a6SAndroid Build Coastguard Worker
607*57b5a4a6SAndroid Build Coastguard Worker```text
608*57b5a4a6SAndroid Build Coastguard Worker[kotlinx.serialization, kotlin, 9000]
609*57b5a4a6SAndroid Build Coastguard Worker```
610*57b5a4a6SAndroid Build Coastguard Worker
611*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST -->
612*57b5a4a6SAndroid Build Coastguard Worker
613*57b5a4a6SAndroid Build Coastguard Worker> By itself, that's a useful feature if we need compute some kind of hashcode or digest for all the data
614*57b5a4a6SAndroid Build Coastguard Worker> that is contained in a serializable object tree.
615*57b5a4a6SAndroid Build Coastguard Worker
616*57b5a4a6SAndroid Build Coastguard Worker### Basic decoder
617*57b5a4a6SAndroid Build Coastguard Worker
618*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
619*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
620*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.descriptors.*
621*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.encoding.*
622*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.*
623*57b5a4a6SAndroid Build Coastguard Worker
624*57b5a4a6SAndroid Build Coastguard Workerclass ListEncoder : AbstractEncoder() {
625*57b5a4a6SAndroid Build Coastguard Worker    val list = mutableListOf<Any>()
626*57b5a4a6SAndroid Build Coastguard Worker
627*57b5a4a6SAndroid Build Coastguard Worker    override val serializersModule: SerializersModule = EmptySerializersModule()
628*57b5a4a6SAndroid Build Coastguard Worker
629*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeValue(value: Any) {
630*57b5a4a6SAndroid Build Coastguard Worker        list.add(value)
631*57b5a4a6SAndroid Build Coastguard Worker    }
632*57b5a4a6SAndroid Build Coastguard Worker}
633*57b5a4a6SAndroid Build Coastguard Worker
634*57b5a4a6SAndroid Build Coastguard Workerfun <T> encodeToList(serializer: SerializationStrategy<T>, value: T): List<Any> {
635*57b5a4a6SAndroid Build Coastguard Worker    val encoder = ListEncoder()
636*57b5a4a6SAndroid Build Coastguard Worker    encoder.encodeSerializableValue(serializer, value)
637*57b5a4a6SAndroid Build Coastguard Worker    return encoder.list
638*57b5a4a6SAndroid Build Coastguard Worker}
639*57b5a4a6SAndroid Build Coastguard Worker
640*57b5a4a6SAndroid Build Coastguard Workerinline fun <reified T> encodeToList(value: T) = encodeToList(serializer(), value)
641*57b5a4a6SAndroid Build Coastguard Worker-->
642*57b5a4a6SAndroid Build Coastguard Worker
643*57b5a4a6SAndroid Build Coastguard WorkerA decoder needs to implement more substance.
644*57b5a4a6SAndroid Build Coastguard Worker
645*57b5a4a6SAndroid Build Coastguard Worker* [decodeValue][AbstractDecoder.decodeValue] &mdash; returns the next value from the list.
646*57b5a4a6SAndroid Build Coastguard Worker* [decodeElementIndex][CompositeDecoder.decodeElementIndex] &mdash; returns the next index of a deserialized value.
647*57b5a4a6SAndroid Build Coastguard Worker  In this primitive format deserialization always happens in order, so we keep track of the index
648*57b5a4a6SAndroid Build Coastguard Worker  in the `elementIndex` variable. See
649*57b5a4a6SAndroid Build Coastguard Worker  the [Hand-written composite serializer](serializers.md#hand-written-composite-serializer) section
650*57b5a4a6SAndroid Build Coastguard Worker  on how it ends up being used.
651*57b5a4a6SAndroid Build Coastguard Worker* [beginStructure][Decoder.beginStructure] &mdash; returns a new instance of the `ListDecoder`, so that
652*57b5a4a6SAndroid Build Coastguard Worker  each structure that is being recursively decoded keeps track of its own `elementIndex` state separately.
653*57b5a4a6SAndroid Build Coastguard Worker
654*57b5a4a6SAndroid Build Coastguard Worker```kotlin
655*57b5a4a6SAndroid Build Coastguard Workerclass ListDecoder(val list: ArrayDeque<Any>) : AbstractDecoder() {
656*57b5a4a6SAndroid Build Coastguard Worker    private var elementIndex = 0
657*57b5a4a6SAndroid Build Coastguard Worker
658*57b5a4a6SAndroid Build Coastguard Worker    override val serializersModule: SerializersModule = EmptySerializersModule()
659*57b5a4a6SAndroid Build Coastguard Worker
660*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeValue(): Any = list.removeFirst()
661*57b5a4a6SAndroid Build Coastguard Worker
662*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
663*57b5a4a6SAndroid Build Coastguard Worker        if (elementIndex == descriptor.elementsCount) return CompositeDecoder.DECODE_DONE
664*57b5a4a6SAndroid Build Coastguard Worker        return elementIndex++
665*57b5a4a6SAndroid Build Coastguard Worker    }
666*57b5a4a6SAndroid Build Coastguard Worker
667*57b5a4a6SAndroid Build Coastguard Worker    override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder =
668*57b5a4a6SAndroid Build Coastguard Worker        ListDecoder(list)
669*57b5a4a6SAndroid Build Coastguard Worker}
670*57b5a4a6SAndroid Build Coastguard Worker```
671*57b5a4a6SAndroid Build Coastguard Worker
672*57b5a4a6SAndroid Build Coastguard WorkerA couple of convenience functions for decoding.
673*57b5a4a6SAndroid Build Coastguard Worker
674*57b5a4a6SAndroid Build Coastguard Worker```kotlin
675*57b5a4a6SAndroid Build Coastguard Workerfun <T> decodeFromList(list: List<Any>, deserializer: DeserializationStrategy<T>): T {
676*57b5a4a6SAndroid Build Coastguard Worker    val decoder = ListDecoder(ArrayDeque(list))
677*57b5a4a6SAndroid Build Coastguard Worker    return decoder.decodeSerializableValue(deserializer)
678*57b5a4a6SAndroid Build Coastguard Worker}
679*57b5a4a6SAndroid Build Coastguard Worker
680*57b5a4a6SAndroid Build Coastguard Workerinline fun <reified T> decodeFromList(list: List<Any>): T = decodeFromList(list, serializer())
681*57b5a4a6SAndroid Build Coastguard Worker```
682*57b5a4a6SAndroid Build Coastguard Worker
683*57b5a4a6SAndroid Build Coastguard WorkerThat is enough to start encoding and decoding basic serializable classes.
684*57b5a4a6SAndroid Build Coastguard Worker
685*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
686*57b5a4a6SAndroid Build Coastguard Worker
687*57b5a4a6SAndroid Build Coastguard Worker@Serializable
688*57b5a4a6SAndroid Build Coastguard Workerdata class Project(val name: String, val owner: User, val votes: Int)
689*57b5a4a6SAndroid Build Coastguard Worker
690*57b5a4a6SAndroid Build Coastguard Worker@Serializable
691*57b5a4a6SAndroid Build Coastguard Workerdata class User(val name: String)
692*57b5a4a6SAndroid Build Coastguard Worker-->
693*57b5a4a6SAndroid Build Coastguard Worker
694*57b5a4a6SAndroid Build Coastguard Worker```kotlin
695*57b5a4a6SAndroid Build Coastguard Workerfun main() {
696*57b5a4a6SAndroid Build Coastguard Worker    val data = Project("kotlinx.serialization",  User("kotlin"), 9000)
697*57b5a4a6SAndroid Build Coastguard Worker    val list = encodeToList(data)
698*57b5a4a6SAndroid Build Coastguard Worker    println(list)
699*57b5a4a6SAndroid Build Coastguard Worker    val obj = decodeFromList<Project>(list)
700*57b5a4a6SAndroid Build Coastguard Worker    println(obj)
701*57b5a4a6SAndroid Build Coastguard Worker}
702*57b5a4a6SAndroid Build Coastguard Worker```
703*57b5a4a6SAndroid Build Coastguard Worker
704*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-11.kt).
705*57b5a4a6SAndroid Build Coastguard Worker
706*57b5a4a6SAndroid Build Coastguard WorkerNow we can convert a list of primitives back to an object tree.
707*57b5a4a6SAndroid Build Coastguard Worker
708*57b5a4a6SAndroid Build Coastguard Worker```text
709*57b5a4a6SAndroid Build Coastguard Worker[kotlinx.serialization, kotlin, 9000]
710*57b5a4a6SAndroid Build Coastguard WorkerProject(name=kotlinx.serialization, owner=User(name=kotlin), votes=9000)
711*57b5a4a6SAndroid Build Coastguard Worker```
712*57b5a4a6SAndroid Build Coastguard Worker
713*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST -->
714*57b5a4a6SAndroid Build Coastguard Worker
715*57b5a4a6SAndroid Build Coastguard Worker### Sequential decoding
716*57b5a4a6SAndroid Build Coastguard Worker
717*57b5a4a6SAndroid Build Coastguard WorkerThe decoder we have implemented keeps track of the `elementIndex` in its state and implements
718*57b5a4a6SAndroid Build Coastguard Worker`decodeElementIndex`. This means that it is going to work with an arbitrary serializer, even the
719*57b5a4a6SAndroid Build Coastguard Workersimple one we wrote in
720*57b5a4a6SAndroid Build Coastguard Workerthe [Hand-written composite serializer](serializers.md#hand-written-composite-serializer) section.
721*57b5a4a6SAndroid Build Coastguard WorkerHowever, this format always stores elements in order, so this bookkeeping is not needed and
722*57b5a4a6SAndroid Build Coastguard Workerundermines decoding performance. All auto-generated serializers on the JVM support
723*57b5a4a6SAndroid Build Coastguard Workerthe [Sequential decoding protocol (experimental)](serializers.md#sequential-decoding-protocol-experimental), and the decoder can indicate
724*57b5a4a6SAndroid Build Coastguard Workerits support by returning `true` from the [CompositeDecoder.decodeSequentially] function.
725*57b5a4a6SAndroid Build Coastguard Worker
726*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
727*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
728*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.descriptors.*
729*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.encoding.*
730*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.*
731*57b5a4a6SAndroid Build Coastguard Worker
732*57b5a4a6SAndroid Build Coastguard Workerclass ListEncoder : AbstractEncoder() {
733*57b5a4a6SAndroid Build Coastguard Worker    val list = mutableListOf<Any>()
734*57b5a4a6SAndroid Build Coastguard Worker
735*57b5a4a6SAndroid Build Coastguard Worker    override val serializersModule: SerializersModule = EmptySerializersModule()
736*57b5a4a6SAndroid Build Coastguard Worker
737*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeValue(value: Any) {
738*57b5a4a6SAndroid Build Coastguard Worker        list.add(value)
739*57b5a4a6SAndroid Build Coastguard Worker    }
740*57b5a4a6SAndroid Build Coastguard Worker}
741*57b5a4a6SAndroid Build Coastguard Worker
742*57b5a4a6SAndroid Build Coastguard Workerfun <T> encodeToList(serializer: SerializationStrategy<T>, value: T): List<Any> {
743*57b5a4a6SAndroid Build Coastguard Worker    val encoder = ListEncoder()
744*57b5a4a6SAndroid Build Coastguard Worker    encoder.encodeSerializableValue(serializer, value)
745*57b5a4a6SAndroid Build Coastguard Worker    return encoder.list
746*57b5a4a6SAndroid Build Coastguard Worker}
747*57b5a4a6SAndroid Build Coastguard Worker
748*57b5a4a6SAndroid Build Coastguard Workerinline fun <reified T> encodeToList(value: T) = encodeToList(serializer(), value)
749*57b5a4a6SAndroid Build Coastguard Worker-->
750*57b5a4a6SAndroid Build Coastguard Worker
751*57b5a4a6SAndroid Build Coastguard Worker```kotlin
752*57b5a4a6SAndroid Build Coastguard Workerclass ListDecoder(val list: ArrayDeque<Any>) : AbstractDecoder() {
753*57b5a4a6SAndroid Build Coastguard Worker    private var elementIndex = 0
754*57b5a4a6SAndroid Build Coastguard Worker
755*57b5a4a6SAndroid Build Coastguard Worker    override val serializersModule: SerializersModule = EmptySerializersModule()
756*57b5a4a6SAndroid Build Coastguard Worker
757*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeValue(): Any = list.removeFirst()
758*57b5a4a6SAndroid Build Coastguard Worker
759*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
760*57b5a4a6SAndroid Build Coastguard Worker        if (elementIndex == descriptor.elementsCount) return CompositeDecoder.DECODE_DONE
761*57b5a4a6SAndroid Build Coastguard Worker        return elementIndex++
762*57b5a4a6SAndroid Build Coastguard Worker    }
763*57b5a4a6SAndroid Build Coastguard Worker
764*57b5a4a6SAndroid Build Coastguard Worker    override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder =
765*57b5a4a6SAndroid Build Coastguard Worker        ListDecoder(list)
766*57b5a4a6SAndroid Build Coastguard Worker
767*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeSequentially(): Boolean = true
768*57b5a4a6SAndroid Build Coastguard Worker}
769*57b5a4a6SAndroid Build Coastguard Worker```
770*57b5a4a6SAndroid Build Coastguard Worker
771*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
772*57b5a4a6SAndroid Build Coastguard Worker
773*57b5a4a6SAndroid Build Coastguard Workerfun <T> decodeFromList(list: List<Any>, deserializer: DeserializationStrategy<T>): T {
774*57b5a4a6SAndroid Build Coastguard Worker    val decoder = ListDecoder(ArrayDeque(list))
775*57b5a4a6SAndroid Build Coastguard Worker    return decoder.decodeSerializableValue(deserializer)
776*57b5a4a6SAndroid Build Coastguard Worker}
777*57b5a4a6SAndroid Build Coastguard Worker
778*57b5a4a6SAndroid Build Coastguard Workerinline fun <reified T> decodeFromList(list: List<Any>): T = decodeFromList(list, serializer())
779*57b5a4a6SAndroid Build Coastguard Worker
780*57b5a4a6SAndroid Build Coastguard Worker@Serializable
781*57b5a4a6SAndroid Build Coastguard Workerdata class Project(val name: String, val owner: User, val votes: Int)
782*57b5a4a6SAndroid Build Coastguard Worker
783*57b5a4a6SAndroid Build Coastguard Worker@Serializable
784*57b5a4a6SAndroid Build Coastguard Workerdata class User(val name: String)
785*57b5a4a6SAndroid Build Coastguard Worker
786*57b5a4a6SAndroid Build Coastguard Workerfun main() {
787*57b5a4a6SAndroid Build Coastguard Worker    val data = Project("kotlinx.serialization",  User("kotlin"), 9000)
788*57b5a4a6SAndroid Build Coastguard Worker    val list = encodeToList(data)
789*57b5a4a6SAndroid Build Coastguard Worker    println(list)
790*57b5a4a6SAndroid Build Coastguard Worker    val obj = decodeFromList<Project>(list)
791*57b5a4a6SAndroid Build Coastguard Worker    println(obj)
792*57b5a4a6SAndroid Build Coastguard Worker}
793*57b5a4a6SAndroid Build Coastguard Worker-->
794*57b5a4a6SAndroid Build Coastguard Worker
795*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-12.kt).
796*57b5a4a6SAndroid Build Coastguard Worker
797*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST
798*57b5a4a6SAndroid Build Coastguard Worker[kotlinx.serialization, kotlin, 9000]
799*57b5a4a6SAndroid Build Coastguard WorkerProject(name=kotlinx.serialization, owner=User(name=kotlin), votes=9000)
800*57b5a4a6SAndroid Build Coastguard Worker-->
801*57b5a4a6SAndroid Build Coastguard Worker
802*57b5a4a6SAndroid Build Coastguard Worker### Adding collection support
803*57b5a4a6SAndroid Build Coastguard Worker
804*57b5a4a6SAndroid Build Coastguard WorkerThis basic format, so far, cannot properly represent collections. In encodes them, but it does not keep
805*57b5a4a6SAndroid Build Coastguard Workertrack of how many elements there are in the collection or where it ends, so it cannot properly decode them.
806*57b5a4a6SAndroid Build Coastguard WorkerFirst, let us add proper support for collections to the encoder by implementing the
807*57b5a4a6SAndroid Build Coastguard Worker[Encoder.beginCollection] function. The `beginCollection` function takes a collection size as a parameter,
808*57b5a4a6SAndroid Build Coastguard Workerso we encode it to add it to the result.
809*57b5a4a6SAndroid Build Coastguard WorkerOur encoder implementation does not keep any state, so it just returns `this` from the `beginCollection` function.
810*57b5a4a6SAndroid Build Coastguard Worker
811*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
812*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
813*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.descriptors.*
814*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.encoding.*
815*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.*
816*57b5a4a6SAndroid Build Coastguard Worker-->
817*57b5a4a6SAndroid Build Coastguard Worker
818*57b5a4a6SAndroid Build Coastguard Worker```kotlin
819*57b5a4a6SAndroid Build Coastguard Workerclass ListEncoder : AbstractEncoder() {
820*57b5a4a6SAndroid Build Coastguard Worker    val list = mutableListOf<Any>()
821*57b5a4a6SAndroid Build Coastguard Worker
822*57b5a4a6SAndroid Build Coastguard Worker    override val serializersModule: SerializersModule = EmptySerializersModule()
823*57b5a4a6SAndroid Build Coastguard Worker
824*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeValue(value: Any) {
825*57b5a4a6SAndroid Build Coastguard Worker        list.add(value)
826*57b5a4a6SAndroid Build Coastguard Worker    }
827*57b5a4a6SAndroid Build Coastguard Worker
828*57b5a4a6SAndroid Build Coastguard Worker    override fun beginCollection(descriptor: SerialDescriptor, collectionSize: Int): CompositeEncoder {
829*57b5a4a6SAndroid Build Coastguard Worker        encodeInt(collectionSize)
830*57b5a4a6SAndroid Build Coastguard Worker        return this
831*57b5a4a6SAndroid Build Coastguard Worker    }
832*57b5a4a6SAndroid Build Coastguard Worker}
833*57b5a4a6SAndroid Build Coastguard Worker```
834*57b5a4a6SAndroid Build Coastguard Worker
835*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
836*57b5a4a6SAndroid Build Coastguard Worker
837*57b5a4a6SAndroid Build Coastguard Workerfun <T> encodeToList(serializer: SerializationStrategy<T>, value: T): List<Any> {
838*57b5a4a6SAndroid Build Coastguard Worker    val encoder = ListEncoder()
839*57b5a4a6SAndroid Build Coastguard Worker    encoder.encodeSerializableValue(serializer, value)
840*57b5a4a6SAndroid Build Coastguard Worker    return encoder.list
841*57b5a4a6SAndroid Build Coastguard Worker}
842*57b5a4a6SAndroid Build Coastguard Worker
843*57b5a4a6SAndroid Build Coastguard Workerinline fun <reified T> encodeToList(value: T) = encodeToList(serializer(), value)
844*57b5a4a6SAndroid Build Coastguard Worker-->
845*57b5a4a6SAndroid Build Coastguard Worker
846*57b5a4a6SAndroid Build Coastguard WorkerThe decoder, for our case, needs to only implement the [CompositeDecoder.decodeCollectionSize] function
847*57b5a4a6SAndroid Build Coastguard Workerin addition to the previous code.
848*57b5a4a6SAndroid Build Coastguard Worker
849*57b5a4a6SAndroid Build Coastguard Worker> The formats that store collection size in advance have to return `true` from `decodeSequentially`.
850*57b5a4a6SAndroid Build Coastguard Worker
851*57b5a4a6SAndroid Build Coastguard Worker```kotlin
852*57b5a4a6SAndroid Build Coastguard Workerclass ListDecoder(val list: ArrayDeque<Any>, var elementsCount: Int = 0) : AbstractDecoder() {
853*57b5a4a6SAndroid Build Coastguard Worker    private var elementIndex = 0
854*57b5a4a6SAndroid Build Coastguard Worker
855*57b5a4a6SAndroid Build Coastguard Worker    override val serializersModule: SerializersModule = EmptySerializersModule()
856*57b5a4a6SAndroid Build Coastguard Worker
857*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeValue(): Any = list.removeFirst()
858*57b5a4a6SAndroid Build Coastguard Worker
859*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
860*57b5a4a6SAndroid Build Coastguard Worker        if (elementIndex == elementsCount) return CompositeDecoder.DECODE_DONE
861*57b5a4a6SAndroid Build Coastguard Worker        return elementIndex++
862*57b5a4a6SAndroid Build Coastguard Worker    }
863*57b5a4a6SAndroid Build Coastguard Worker
864*57b5a4a6SAndroid Build Coastguard Worker    override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder =
865*57b5a4a6SAndroid Build Coastguard Worker        ListDecoder(list, descriptor.elementsCount)
866*57b5a4a6SAndroid Build Coastguard Worker
867*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeSequentially(): Boolean = true
868*57b5a4a6SAndroid Build Coastguard Worker
869*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeCollectionSize(descriptor: SerialDescriptor): Int =
870*57b5a4a6SAndroid Build Coastguard Worker        decodeInt().also { elementsCount = it }
871*57b5a4a6SAndroid Build Coastguard Worker}
872*57b5a4a6SAndroid Build Coastguard Worker```
873*57b5a4a6SAndroid Build Coastguard Worker
874*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
875*57b5a4a6SAndroid Build Coastguard Worker
876*57b5a4a6SAndroid Build Coastguard Workerfun <T> decodeFromList(list: List<Any>, deserializer: DeserializationStrategy<T>): T {
877*57b5a4a6SAndroid Build Coastguard Worker    val decoder = ListDecoder(ArrayDeque(list))
878*57b5a4a6SAndroid Build Coastguard Worker    return decoder.decodeSerializableValue(deserializer)
879*57b5a4a6SAndroid Build Coastguard Worker}
880*57b5a4a6SAndroid Build Coastguard Worker
881*57b5a4a6SAndroid Build Coastguard Workerinline fun <reified T> decodeFromList(list: List<Any>): T = decodeFromList(list, serializer())
882*57b5a4a6SAndroid Build Coastguard Worker-->
883*57b5a4a6SAndroid Build Coastguard Worker
884*57b5a4a6SAndroid Build Coastguard WorkerThat is all that is needed to support collections and maps.
885*57b5a4a6SAndroid Build Coastguard Worker
886*57b5a4a6SAndroid Build Coastguard Worker```kotlin
887*57b5a4a6SAndroid Build Coastguard Worker@Serializable
888*57b5a4a6SAndroid Build Coastguard Workerdata class Project(val name: String, val owners: List<User>, val votes: Int)
889*57b5a4a6SAndroid Build Coastguard Worker
890*57b5a4a6SAndroid Build Coastguard Worker@Serializable
891*57b5a4a6SAndroid Build Coastguard Workerdata class User(val name: String)
892*57b5a4a6SAndroid Build Coastguard Worker
893*57b5a4a6SAndroid Build Coastguard Workerfun main() {
894*57b5a4a6SAndroid Build Coastguard Worker    val data = Project("kotlinx.serialization",  listOf(User("kotlin"), User("jetbrains")), 9000)
895*57b5a4a6SAndroid Build Coastguard Worker    val list = encodeToList(data)
896*57b5a4a6SAndroid Build Coastguard Worker    println(list)
897*57b5a4a6SAndroid Build Coastguard Worker    val obj = decodeFromList<Project>(list)
898*57b5a4a6SAndroid Build Coastguard Worker    println(obj)
899*57b5a4a6SAndroid Build Coastguard Worker}
900*57b5a4a6SAndroid Build Coastguard Worker```
901*57b5a4a6SAndroid Build Coastguard Worker
902*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-13.kt).
903*57b5a4a6SAndroid Build Coastguard Worker
904*57b5a4a6SAndroid Build Coastguard WorkerWe see the size of the list added to the result, letting the decoder know where to stop.
905*57b5a4a6SAndroid Build Coastguard Worker
906*57b5a4a6SAndroid Build Coastguard Worker```text
907*57b5a4a6SAndroid Build Coastguard Worker[kotlinx.serialization, 2, kotlin, jetbrains, 9000]
908*57b5a4a6SAndroid Build Coastguard WorkerProject(name=kotlinx.serialization, owners=[User(name=kotlin), User(name=jetbrains)], votes=9000)
909*57b5a4a6SAndroid Build Coastguard Worker```
910*57b5a4a6SAndroid Build Coastguard Worker
911*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST -->
912*57b5a4a6SAndroid Build Coastguard Worker
913*57b5a4a6SAndroid Build Coastguard Worker### Adding null support
914*57b5a4a6SAndroid Build Coastguard Worker
915*57b5a4a6SAndroid Build Coastguard WorkerOur trivial format does not support `null` values so far. For nullable types we need to add some kind
916*57b5a4a6SAndroid Build Coastguard Workerof "null indicator", telling whether the upcoming value is null or not.
917*57b5a4a6SAndroid Build Coastguard Worker
918*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
919*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
920*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.descriptors.*
921*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.encoding.*
922*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.*
923*57b5a4a6SAndroid Build Coastguard Worker
924*57b5a4a6SAndroid Build Coastguard Workerclass ListEncoder : AbstractEncoder() {
925*57b5a4a6SAndroid Build Coastguard Worker    val list = mutableListOf<Any>()
926*57b5a4a6SAndroid Build Coastguard Worker
927*57b5a4a6SAndroid Build Coastguard Worker    override val serializersModule: SerializersModule = EmptySerializersModule()
928*57b5a4a6SAndroid Build Coastguard Worker
929*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeValue(value: Any) {
930*57b5a4a6SAndroid Build Coastguard Worker        list.add(value)
931*57b5a4a6SAndroid Build Coastguard Worker    }
932*57b5a4a6SAndroid Build Coastguard Worker
933*57b5a4a6SAndroid Build Coastguard Worker    override fun beginCollection(descriptor: SerialDescriptor, collectionSize: Int): CompositeEncoder {
934*57b5a4a6SAndroid Build Coastguard Worker        encodeInt(collectionSize)
935*57b5a4a6SAndroid Build Coastguard Worker        return this
936*57b5a4a6SAndroid Build Coastguard Worker    }
937*57b5a4a6SAndroid Build Coastguard Worker-->
938*57b5a4a6SAndroid Build Coastguard Worker
939*57b5a4a6SAndroid Build Coastguard WorkerIn the encoder implementation we override [Encoder.encodeNull] and [Encoder.encodeNotNullMark].
940*57b5a4a6SAndroid Build Coastguard Worker
941*57b5a4a6SAndroid Build Coastguard Worker```kotlin
942*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeNull() = encodeValue("NULL")
943*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeNotNullMark() = encodeValue("!!")
944*57b5a4a6SAndroid Build Coastguard Worker```
945*57b5a4a6SAndroid Build Coastguard Worker
946*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
947*57b5a4a6SAndroid Build Coastguard Worker}
948*57b5a4a6SAndroid Build Coastguard Worker
949*57b5a4a6SAndroid Build Coastguard Workerfun <T> encodeToList(serializer: SerializationStrategy<T>, value: T): List<Any> {
950*57b5a4a6SAndroid Build Coastguard Worker    val encoder = ListEncoder()
951*57b5a4a6SAndroid Build Coastguard Worker    encoder.encodeSerializableValue(serializer, value)
952*57b5a4a6SAndroid Build Coastguard Worker    return encoder.list
953*57b5a4a6SAndroid Build Coastguard Worker}
954*57b5a4a6SAndroid Build Coastguard Worker
955*57b5a4a6SAndroid Build Coastguard Workerinline fun <reified T> encodeToList(value: T) = encodeToList(serializer(), value)
956*57b5a4a6SAndroid Build Coastguard Worker
957*57b5a4a6SAndroid Build Coastguard Workerclass ListDecoder(val list: ArrayDeque<Any>, var elementsCount: Int = 0) : AbstractDecoder() {
958*57b5a4a6SAndroid Build Coastguard Worker    private var elementIndex = 0
959*57b5a4a6SAndroid Build Coastguard Worker
960*57b5a4a6SAndroid Build Coastguard Worker    override val serializersModule: SerializersModule = EmptySerializersModule()
961*57b5a4a6SAndroid Build Coastguard Worker
962*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeValue(): Any = list.removeFirst()
963*57b5a4a6SAndroid Build Coastguard Worker
964*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
965*57b5a4a6SAndroid Build Coastguard Worker        if (elementIndex == elementsCount) return CompositeDecoder.DECODE_DONE
966*57b5a4a6SAndroid Build Coastguard Worker        return elementIndex++
967*57b5a4a6SAndroid Build Coastguard Worker    }
968*57b5a4a6SAndroid Build Coastguard Worker
969*57b5a4a6SAndroid Build Coastguard Worker    override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder =
970*57b5a4a6SAndroid Build Coastguard Worker        ListDecoder(list, descriptor.elementsCount)
971*57b5a4a6SAndroid Build Coastguard Worker
972*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeSequentially(): Boolean = true
973*57b5a4a6SAndroid Build Coastguard Worker
974*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeCollectionSize(descriptor: SerialDescriptor): Int =
975*57b5a4a6SAndroid Build Coastguard Worker        decodeInt().also { elementsCount = it }
976*57b5a4a6SAndroid Build Coastguard Worker-->
977*57b5a4a6SAndroid Build Coastguard Worker
978*57b5a4a6SAndroid Build Coastguard WorkerIn the decoder implementation we override [Decoder.decodeNotNullMark].
979*57b5a4a6SAndroid Build Coastguard Worker
980*57b5a4a6SAndroid Build Coastguard Worker```kotlin
981*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeNotNullMark(): Boolean = decodeString() != "NULL"
982*57b5a4a6SAndroid Build Coastguard Worker```
983*57b5a4a6SAndroid Build Coastguard Worker
984*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
985*57b5a4a6SAndroid Build Coastguard Worker}
986*57b5a4a6SAndroid Build Coastguard Worker
987*57b5a4a6SAndroid Build Coastguard Workerfun <T> decodeFromList(list: List<Any>, deserializer: DeserializationStrategy<T>): T {
988*57b5a4a6SAndroid Build Coastguard Worker    val decoder = ListDecoder(ArrayDeque(list))
989*57b5a4a6SAndroid Build Coastguard Worker    return decoder.decodeSerializableValue(deserializer)
990*57b5a4a6SAndroid Build Coastguard Worker}
991*57b5a4a6SAndroid Build Coastguard Worker
992*57b5a4a6SAndroid Build Coastguard Workerinline fun <reified T> decodeFromList(list: List<Any>): T = decodeFromList(list, serializer())
993*57b5a4a6SAndroid Build Coastguard Worker-->
994*57b5a4a6SAndroid Build Coastguard Worker
995*57b5a4a6SAndroid Build Coastguard WorkerLet us test nullable properties both with not-null and null values.
996*57b5a4a6SAndroid Build Coastguard Worker
997*57b5a4a6SAndroid Build Coastguard Worker```kotlin
998*57b5a4a6SAndroid Build Coastguard Worker@Serializable
999*57b5a4a6SAndroid Build Coastguard Workerdata class Project(val name: String, val owner: User?, val votes: Int?)
1000*57b5a4a6SAndroid Build Coastguard Worker
1001*57b5a4a6SAndroid Build Coastguard Worker@Serializable
1002*57b5a4a6SAndroid Build Coastguard Workerdata class User(val name: String)
1003*57b5a4a6SAndroid Build Coastguard Worker
1004*57b5a4a6SAndroid Build Coastguard Workerfun main() {
1005*57b5a4a6SAndroid Build Coastguard Worker    val data = Project("kotlinx.serialization",  User("kotlin") , null)
1006*57b5a4a6SAndroid Build Coastguard Worker    val list = encodeToList(data)
1007*57b5a4a6SAndroid Build Coastguard Worker    println(list)
1008*57b5a4a6SAndroid Build Coastguard Worker    val obj = decodeFromList<Project>(list)
1009*57b5a4a6SAndroid Build Coastguard Worker    println(obj)
1010*57b5a4a6SAndroid Build Coastguard Worker}
1011*57b5a4a6SAndroid Build Coastguard Worker
1012*57b5a4a6SAndroid Build Coastguard Worker```
1013*57b5a4a6SAndroid Build Coastguard Worker
1014*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-14.kt).
1015*57b5a4a6SAndroid Build Coastguard Worker
1016*57b5a4a6SAndroid Build Coastguard WorkerIn the output we see how not-null`!!` and `NULL` marks are used.
1017*57b5a4a6SAndroid Build Coastguard Worker
1018*57b5a4a6SAndroid Build Coastguard Worker```text
1019*57b5a4a6SAndroid Build Coastguard Worker[kotlinx.serialization, !!, kotlin, NULL]
1020*57b5a4a6SAndroid Build Coastguard WorkerProject(name=kotlinx.serialization, owner=User(name=kotlin), votes=null)
1021*57b5a4a6SAndroid Build Coastguard Worker```
1022*57b5a4a6SAndroid Build Coastguard Worker
1023*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST -->
1024*57b5a4a6SAndroid Build Coastguard Worker
1025*57b5a4a6SAndroid Build Coastguard Worker### Efficient binary format
1026*57b5a4a6SAndroid Build Coastguard Worker
1027*57b5a4a6SAndroid Build Coastguard WorkerNow we are ready for an example of an efficient binary format. We are going to write data to the
1028*57b5a4a6SAndroid Build Coastguard Worker[java.io.DataOutput] implementation. Instead of `encodeValue` we must override the individual
1029*57b5a4a6SAndroid Build Coastguard Worker`encodeXxx` functions for each of ten [primitives](builtin-classes.md#primitives) in the encoder.
1030*57b5a4a6SAndroid Build Coastguard Worker
1031*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
1032*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
1033*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.Serializable
1034*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.descriptors.*
1035*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.encoding.*
1036*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.*
1037*57b5a4a6SAndroid Build Coastguard Workerimport java.io.*
1038*57b5a4a6SAndroid Build Coastguard Worker-->
1039*57b5a4a6SAndroid Build Coastguard Worker
1040*57b5a4a6SAndroid Build Coastguard Worker```kotlin
1041*57b5a4a6SAndroid Build Coastguard Workerclass DataOutputEncoder(val output: DataOutput) : AbstractEncoder() {
1042*57b5a4a6SAndroid Build Coastguard Worker    override val serializersModule: SerializersModule = EmptySerializersModule()
1043*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeBoolean(value: Boolean) = output.writeByte(if (value) 1 else 0)
1044*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeByte(value: Byte) = output.writeByte(value.toInt())
1045*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeShort(value: Short) = output.writeShort(value.toInt())
1046*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeInt(value: Int) = output.writeInt(value)
1047*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeLong(value: Long) = output.writeLong(value)
1048*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeFloat(value: Float) = output.writeFloat(value)
1049*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeDouble(value: Double) = output.writeDouble(value)
1050*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeChar(value: Char) = output.writeChar(value.code)
1051*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeString(value: String) = output.writeUTF(value)
1052*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int) = output.writeInt(index)
1053*57b5a4a6SAndroid Build Coastguard Worker
1054*57b5a4a6SAndroid Build Coastguard Worker    override fun beginCollection(descriptor: SerialDescriptor, collectionSize: Int): CompositeEncoder {
1055*57b5a4a6SAndroid Build Coastguard Worker        encodeInt(collectionSize)
1056*57b5a4a6SAndroid Build Coastguard Worker        return this
1057*57b5a4a6SAndroid Build Coastguard Worker    }
1058*57b5a4a6SAndroid Build Coastguard Worker
1059*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeNull() = encodeBoolean(false)
1060*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeNotNullMark() = encodeBoolean(true)
1061*57b5a4a6SAndroid Build Coastguard Worker}
1062*57b5a4a6SAndroid Build Coastguard Worker```
1063*57b5a4a6SAndroid Build Coastguard Worker
1064*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
1065*57b5a4a6SAndroid Build Coastguard Worker
1066*57b5a4a6SAndroid Build Coastguard Workerfun <T> encodeTo(output: DataOutput, serializer: SerializationStrategy<T>, value: T) {
1067*57b5a4a6SAndroid Build Coastguard Worker    val encoder = DataOutputEncoder(output)
1068*57b5a4a6SAndroid Build Coastguard Worker    encoder.encodeSerializableValue(serializer, value)
1069*57b5a4a6SAndroid Build Coastguard Worker}
1070*57b5a4a6SAndroid Build Coastguard Worker
1071*57b5a4a6SAndroid Build Coastguard Workerinline fun <reified T> encodeTo(output: DataOutput, value: T) = encodeTo(output, serializer(), value)
1072*57b5a4a6SAndroid Build Coastguard Worker-->
1073*57b5a4a6SAndroid Build Coastguard Worker
1074*57b5a4a6SAndroid Build Coastguard WorkerThe decoder implementation mirrors encoder's implementation overriding all the primitive `decodeXxx` functions.
1075*57b5a4a6SAndroid Build Coastguard Worker
1076*57b5a4a6SAndroid Build Coastguard Worker```kotlin
1077*57b5a4a6SAndroid Build Coastguard Workerclass DataInputDecoder(val input: DataInput, var elementsCount: Int = 0) : AbstractDecoder() {
1078*57b5a4a6SAndroid Build Coastguard Worker    private var elementIndex = 0
1079*57b5a4a6SAndroid Build Coastguard Worker    override val serializersModule: SerializersModule = EmptySerializersModule()
1080*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeBoolean(): Boolean = input.readByte().toInt() != 0
1081*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeByte(): Byte = input.readByte()
1082*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeShort(): Short = input.readShort()
1083*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeInt(): Int = input.readInt()
1084*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeLong(): Long = input.readLong()
1085*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeFloat(): Float = input.readFloat()
1086*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeDouble(): Double = input.readDouble()
1087*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeChar(): Char = input.readChar()
1088*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeString(): String = input.readUTF()
1089*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeEnum(enumDescriptor: SerialDescriptor): Int = input.readInt()
1090*57b5a4a6SAndroid Build Coastguard Worker
1091*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
1092*57b5a4a6SAndroid Build Coastguard Worker        if (elementIndex == elementsCount) return CompositeDecoder.DECODE_DONE
1093*57b5a4a6SAndroid Build Coastguard Worker        return elementIndex++
1094*57b5a4a6SAndroid Build Coastguard Worker    }
1095*57b5a4a6SAndroid Build Coastguard Worker
1096*57b5a4a6SAndroid Build Coastguard Worker    override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder =
1097*57b5a4a6SAndroid Build Coastguard Worker        DataInputDecoder(input, descriptor.elementsCount)
1098*57b5a4a6SAndroid Build Coastguard Worker
1099*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeSequentially(): Boolean = true
1100*57b5a4a6SAndroid Build Coastguard Worker
1101*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeCollectionSize(descriptor: SerialDescriptor): Int =
1102*57b5a4a6SAndroid Build Coastguard Worker        decodeInt().also { elementsCount = it }
1103*57b5a4a6SAndroid Build Coastguard Worker
1104*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeNotNullMark(): Boolean = decodeBoolean()
1105*57b5a4a6SAndroid Build Coastguard Worker}
1106*57b5a4a6SAndroid Build Coastguard Worker```
1107*57b5a4a6SAndroid Build Coastguard Worker
1108*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
1109*57b5a4a6SAndroid Build Coastguard Worker
1110*57b5a4a6SAndroid Build Coastguard Workerfun <T> decodeFrom(input: DataInput, deserializer: DeserializationStrategy<T>): T {
1111*57b5a4a6SAndroid Build Coastguard Worker    val decoder = DataInputDecoder(input)
1112*57b5a4a6SAndroid Build Coastguard Worker    return decoder.decodeSerializableValue(deserializer)
1113*57b5a4a6SAndroid Build Coastguard Worker}
1114*57b5a4a6SAndroid Build Coastguard Worker
1115*57b5a4a6SAndroid Build Coastguard Workerinline fun <reified T> decodeFrom(input: DataInput): T = decodeFrom(input, serializer())
1116*57b5a4a6SAndroid Build Coastguard Worker
1117*57b5a4a6SAndroid Build Coastguard Workerfun ByteArray.toAsciiHexString() = joinToString("") {
1118*57b5a4a6SAndroid Build Coastguard Worker    if (it in 32..127) it.toInt().toChar().toString() else
1119*57b5a4a6SAndroid Build Coastguard Worker        "{${it.toUByte().toString(16).padStart(2, '0').uppercase()}}"
1120*57b5a4a6SAndroid Build Coastguard Worker}
1121*57b5a4a6SAndroid Build Coastguard Worker-->
1122*57b5a4a6SAndroid Build Coastguard Worker
1123*57b5a4a6SAndroid Build Coastguard WorkerWe can now serialize and deserialize arbitrary data. For example, the same classes as were
1124*57b5a4a6SAndroid Build Coastguard Workerused in the [CBOR (experimental)](#cbor-experimental) and [ProtoBuf (experimental)](#protobuf-experimental) sections.
1125*57b5a4a6SAndroid Build Coastguard Worker
1126*57b5a4a6SAndroid Build Coastguard Worker```kotlin
1127*57b5a4a6SAndroid Build Coastguard Worker@Serializable
1128*57b5a4a6SAndroid Build Coastguard Workerdata class Project(val name: String, val language: String)
1129*57b5a4a6SAndroid Build Coastguard Worker
1130*57b5a4a6SAndroid Build Coastguard Workerfun main() {
1131*57b5a4a6SAndroid Build Coastguard Worker    val data = Project("kotlinx.serialization", "Kotlin")
1132*57b5a4a6SAndroid Build Coastguard Worker    val output = ByteArrayOutputStream()
1133*57b5a4a6SAndroid Build Coastguard Worker    encodeTo(DataOutputStream(output), data)
1134*57b5a4a6SAndroid Build Coastguard Worker    val bytes = output.toByteArray()
1135*57b5a4a6SAndroid Build Coastguard Worker    println(bytes.toAsciiHexString())
1136*57b5a4a6SAndroid Build Coastguard Worker    val input = ByteArrayInputStream(bytes)
1137*57b5a4a6SAndroid Build Coastguard Worker    val obj = decodeFrom<Project>(DataInputStream(input))
1138*57b5a4a6SAndroid Build Coastguard Worker    println(obj)
1139*57b5a4a6SAndroid Build Coastguard Worker}
1140*57b5a4a6SAndroid Build Coastguard Worker```
1141*57b5a4a6SAndroid Build Coastguard Worker
1142*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-15.kt).
1143*57b5a4a6SAndroid Build Coastguard Worker
1144*57b5a4a6SAndroid Build Coastguard WorkerAs we can see, the result is a dense binary format that only contains the data that is being serialized.
1145*57b5a4a6SAndroid Build Coastguard WorkerIt can be easily tweaked for any kind of domain-specific compact encoding.
1146*57b5a4a6SAndroid Build Coastguard Worker
1147*57b5a4a6SAndroid Build Coastguard Worker```text
1148*57b5a4a6SAndroid Build Coastguard Worker{00}{15}kotlinx.serialization{00}{06}Kotlin
1149*57b5a4a6SAndroid Build Coastguard WorkerProject(name=kotlinx.serialization, language=Kotlin)
1150*57b5a4a6SAndroid Build Coastguard Worker```
1151*57b5a4a6SAndroid Build Coastguard Worker
1152*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST -->
1153*57b5a4a6SAndroid Build Coastguard Worker
1154*57b5a4a6SAndroid Build Coastguard Worker### Format-specific types
1155*57b5a4a6SAndroid Build Coastguard Worker
1156*57b5a4a6SAndroid Build Coastguard WorkerA format implementation might provide special support for data types that are not among the list of primitive
1157*57b5a4a6SAndroid Build Coastguard Workertypes in Kotlin Serialization, and do not have a corresponding `encodeXxx`/`decodeXxx` function.
1158*57b5a4a6SAndroid Build Coastguard WorkerIn the encoder this is achieved by overriding the
1159*57b5a4a6SAndroid Build Coastguard Worker[`encodeSerializableValue(serializer, value)`][Encoder.encodeSerializableValue] function.
1160*57b5a4a6SAndroid Build Coastguard Worker
1161*57b5a4a6SAndroid Build Coastguard WorkerIn our `DataOutput` format example we might want to provide a specialized efficient data path for serializing an array
1162*57b5a4a6SAndroid Build Coastguard Workerof bytes since [DataOutput][java.io.DataOutput] has a special method for this purpose.
1163*57b5a4a6SAndroid Build Coastguard Worker
1164*57b5a4a6SAndroid Build Coastguard WorkerDetection of the type is performed by looking at the `serializer.descriptor`, not by checking the type of the `value`
1165*57b5a4a6SAndroid Build Coastguard Workerbeing serialized, so we fetch the builtin [KSerializer] instance for `ByteArray` type.
1166*57b5a4a6SAndroid Build Coastguard Worker
1167*57b5a4a6SAndroid Build Coastguard Worker> This an important difference. This way our format implementation properly supports
1168*57b5a4a6SAndroid Build Coastguard Worker> [Custom serializers](serializers.md#custom-serializers) that a user might specify for a type that just happens
1169*57b5a4a6SAndroid Build Coastguard Worker> to be internally represented as a byte array, but need a different serial representation.
1170*57b5a4a6SAndroid Build Coastguard Worker
1171*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
1172*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.*
1173*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.Serializable
1174*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.descriptors.*
1175*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.*
1176*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.encoding.*
1177*57b5a4a6SAndroid Build Coastguard Workerimport java.io.*
1178*57b5a4a6SAndroid Build Coastguard Worker-->
1179*57b5a4a6SAndroid Build Coastguard Worker
1180*57b5a4a6SAndroid Build Coastguard Worker```kotlin
1181*57b5a4a6SAndroid Build Coastguard Workerprivate val byteArraySerializer = serializer<ByteArray>()
1182*57b5a4a6SAndroid Build Coastguard Worker```
1183*57b5a4a6SAndroid Build Coastguard Worker
1184*57b5a4a6SAndroid Build Coastguard Worker> Specifically for byte arrays, we could have also used the builtin
1185*57b5a4a6SAndroid Build Coastguard Worker> [ByteArraySerializer][kotlinx.serialization.builtins.ByteArraySerializer()] function.
1186*57b5a4a6SAndroid Build Coastguard Worker
1187*57b5a4a6SAndroid Build Coastguard WorkerWe add the corresponding code to the [Encoder] implementation of our
1188*57b5a4a6SAndroid Build Coastguard Worker[Efficient binary format](#efficient-binary-format). To make our `ByteArray` encoding even more efficient,
1189*57b5a4a6SAndroid Build Coastguard Workerwe add a trivial implementation of `encodeCompactSize` function that uses only one byte to represent
1190*57b5a4a6SAndroid Build Coastguard Workera size of up to 254 bytes.
1191*57b5a4a6SAndroid Build Coastguard Worker
1192*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
1193*57b5a4a6SAndroid Build Coastguard Workerclass DataOutputEncoder(val output: DataOutput) : AbstractEncoder() {
1194*57b5a4a6SAndroid Build Coastguard Worker    override val serializersModule: SerializersModule = EmptySerializersModule()
1195*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeBoolean(value: Boolean) = output.writeByte(if (value) 1 else 0)
1196*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeByte(value: Byte) = output.writeByte(value.toInt())
1197*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeShort(value: Short) = output.writeShort(value.toInt())
1198*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeInt(value: Int) = output.writeInt(value)
1199*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeLong(value: Long) = output.writeLong(value)
1200*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeFloat(value: Float) = output.writeFloat(value)
1201*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeDouble(value: Double) = output.writeDouble(value)
1202*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeChar(value: Char) = output.writeChar(value.code)
1203*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeString(value: String) = output.writeUTF(value)
1204*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int) = output.writeInt(index)
1205*57b5a4a6SAndroid Build Coastguard Worker
1206*57b5a4a6SAndroid Build Coastguard Worker    override fun beginCollection(descriptor: SerialDescriptor, collectionSize: Int): CompositeEncoder {
1207*57b5a4a6SAndroid Build Coastguard Worker        encodeInt(collectionSize)
1208*57b5a4a6SAndroid Build Coastguard Worker        return this
1209*57b5a4a6SAndroid Build Coastguard Worker    }
1210*57b5a4a6SAndroid Build Coastguard Worker
1211*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeNull() = encodeBoolean(false)
1212*57b5a4a6SAndroid Build Coastguard Worker    override fun encodeNotNullMark() = encodeBoolean(true)
1213*57b5a4a6SAndroid Build Coastguard Worker-->
1214*57b5a4a6SAndroid Build Coastguard Worker
1215*57b5a4a6SAndroid Build Coastguard Worker```kotlin
1216*57b5a4a6SAndroid Build Coastguard Worker    override fun <T> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) {
1217*57b5a4a6SAndroid Build Coastguard Worker        if (serializer.descriptor == byteArraySerializer.descriptor)
1218*57b5a4a6SAndroid Build Coastguard Worker            encodeByteArray(value as ByteArray)
1219*57b5a4a6SAndroid Build Coastguard Worker        else
1220*57b5a4a6SAndroid Build Coastguard Worker            super.encodeSerializableValue(serializer, value)
1221*57b5a4a6SAndroid Build Coastguard Worker    }
1222*57b5a4a6SAndroid Build Coastguard Worker
1223*57b5a4a6SAndroid Build Coastguard Worker    private fun encodeByteArray(bytes: ByteArray) {
1224*57b5a4a6SAndroid Build Coastguard Worker        encodeCompactSize(bytes.size)
1225*57b5a4a6SAndroid Build Coastguard Worker        output.write(bytes)
1226*57b5a4a6SAndroid Build Coastguard Worker    }
1227*57b5a4a6SAndroid Build Coastguard Worker
1228*57b5a4a6SAndroid Build Coastguard Worker    private fun encodeCompactSize(value: Int) {
1229*57b5a4a6SAndroid Build Coastguard Worker        if (value < 0xff) {
1230*57b5a4a6SAndroid Build Coastguard Worker            output.writeByte(value)
1231*57b5a4a6SAndroid Build Coastguard Worker        } else {
1232*57b5a4a6SAndroid Build Coastguard Worker            output.writeByte(0xff)
1233*57b5a4a6SAndroid Build Coastguard Worker            output.writeInt(value)
1234*57b5a4a6SAndroid Build Coastguard Worker        }
1235*57b5a4a6SAndroid Build Coastguard Worker    }
1236*57b5a4a6SAndroid Build Coastguard Worker```
1237*57b5a4a6SAndroid Build Coastguard Worker
1238*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
1239*57b5a4a6SAndroid Build Coastguard Worker}
1240*57b5a4a6SAndroid Build Coastguard Worker
1241*57b5a4a6SAndroid Build Coastguard Workerfun <T> encodeTo(output: DataOutput, serializer: SerializationStrategy<T>, value: T) {
1242*57b5a4a6SAndroid Build Coastguard Worker    val encoder = DataOutputEncoder(output)
1243*57b5a4a6SAndroid Build Coastguard Worker    encoder.encodeSerializableValue(serializer, value)
1244*57b5a4a6SAndroid Build Coastguard Worker}
1245*57b5a4a6SAndroid Build Coastguard Worker
1246*57b5a4a6SAndroid Build Coastguard Workerinline fun <reified T> encodeTo(output: DataOutput, value: T) = encodeTo(output, serializer(), value)
1247*57b5a4a6SAndroid Build Coastguard Worker
1248*57b5a4a6SAndroid Build Coastguard Workerclass DataInputDecoder(val input: DataInput, var elementsCount: Int = 0) : AbstractDecoder() {
1249*57b5a4a6SAndroid Build Coastguard Worker    private var elementIndex = 0
1250*57b5a4a6SAndroid Build Coastguard Worker    override val serializersModule: SerializersModule = EmptySerializersModule()
1251*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeBoolean(): Boolean = input.readByte().toInt() != 0
1252*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeByte(): Byte = input.readByte()
1253*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeShort(): Short = input.readShort()
1254*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeInt(): Int = input.readInt()
1255*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeLong(): Long = input.readLong()
1256*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeFloat(): Float = input.readFloat()
1257*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeDouble(): Double = input.readDouble()
1258*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeChar(): Char = input.readChar()
1259*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeString(): String = input.readUTF()
1260*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeEnum(enumDescriptor: SerialDescriptor): Int = input.readInt()
1261*57b5a4a6SAndroid Build Coastguard Worker
1262*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeElementIndex(descriptor: SerialDescriptor): Int {
1263*57b5a4a6SAndroid Build Coastguard Worker        if (elementIndex == elementsCount) return CompositeDecoder.DECODE_DONE
1264*57b5a4a6SAndroid Build Coastguard Worker        return elementIndex++
1265*57b5a4a6SAndroid Build Coastguard Worker    }
1266*57b5a4a6SAndroid Build Coastguard Worker
1267*57b5a4a6SAndroid Build Coastguard Worker    override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder =
1268*57b5a4a6SAndroid Build Coastguard Worker        DataInputDecoder(input, descriptor.elementsCount)
1269*57b5a4a6SAndroid Build Coastguard Worker
1270*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeSequentially(): Boolean = true
1271*57b5a4a6SAndroid Build Coastguard Worker
1272*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeCollectionSize(descriptor: SerialDescriptor): Int =
1273*57b5a4a6SAndroid Build Coastguard Worker        decodeInt().also { elementsCount = it }
1274*57b5a4a6SAndroid Build Coastguard Worker
1275*57b5a4a6SAndroid Build Coastguard Worker    override fun decodeNotNullMark(): Boolean = decodeBoolean()
1276*57b5a4a6SAndroid Build Coastguard Worker-->
1277*57b5a4a6SAndroid Build Coastguard Worker
1278*57b5a4a6SAndroid Build Coastguard WorkerA similar code is added to the [Decoder] implementation. Here we override
1279*57b5a4a6SAndroid Build Coastguard Workerthe [decodeSerializableValue][Decoder.decodeSerializableValue] function.
1280*57b5a4a6SAndroid Build Coastguard Worker
1281*57b5a4a6SAndroid Build Coastguard Worker```kotlin
1282*57b5a4a6SAndroid Build Coastguard Worker    @Suppress("UNCHECKED_CAST")
1283*57b5a4a6SAndroid Build Coastguard Worker    override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>, previousValue: T?): T =
1284*57b5a4a6SAndroid Build Coastguard Worker        if (deserializer.descriptor == byteArraySerializer.descriptor)
1285*57b5a4a6SAndroid Build Coastguard Worker            decodeByteArray() as T
1286*57b5a4a6SAndroid Build Coastguard Worker        else
1287*57b5a4a6SAndroid Build Coastguard Worker            super.decodeSerializableValue(deserializer, previousValue)
1288*57b5a4a6SAndroid Build Coastguard Worker
1289*57b5a4a6SAndroid Build Coastguard Worker    private fun decodeByteArray(): ByteArray {
1290*57b5a4a6SAndroid Build Coastguard Worker        val bytes = ByteArray(decodeCompactSize())
1291*57b5a4a6SAndroid Build Coastguard Worker        input.readFully(bytes)
1292*57b5a4a6SAndroid Build Coastguard Worker        return bytes
1293*57b5a4a6SAndroid Build Coastguard Worker    }
1294*57b5a4a6SAndroid Build Coastguard Worker
1295*57b5a4a6SAndroid Build Coastguard Worker    private fun decodeCompactSize(): Int {
1296*57b5a4a6SAndroid Build Coastguard Worker        val byte = input.readByte().toInt() and 0xff
1297*57b5a4a6SAndroid Build Coastguard Worker        if (byte < 0xff) return byte
1298*57b5a4a6SAndroid Build Coastguard Worker        return input.readInt()
1299*57b5a4a6SAndroid Build Coastguard Worker    }
1300*57b5a4a6SAndroid Build Coastguard Worker```
1301*57b5a4a6SAndroid Build Coastguard Worker
1302*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE
1303*57b5a4a6SAndroid Build Coastguard Worker}
1304*57b5a4a6SAndroid Build Coastguard Worker
1305*57b5a4a6SAndroid Build Coastguard Workerfun <T> decodeFrom(input: DataInput, deserializer: DeserializationStrategy<T>): T {
1306*57b5a4a6SAndroid Build Coastguard Worker    val decoder = DataInputDecoder(input)
1307*57b5a4a6SAndroid Build Coastguard Worker    return decoder.decodeSerializableValue(deserializer)
1308*57b5a4a6SAndroid Build Coastguard Worker}
1309*57b5a4a6SAndroid Build Coastguard Worker
1310*57b5a4a6SAndroid Build Coastguard Workerinline fun <reified T> decodeFrom(input: DataInput): T = decodeFrom(input, serializer())
1311*57b5a4a6SAndroid Build Coastguard Worker
1312*57b5a4a6SAndroid Build Coastguard Workerfun ByteArray.toAsciiHexString() = joinToString("") {
1313*57b5a4a6SAndroid Build Coastguard Worker    if (it in 32..127) it.toInt().toChar().toString() else
1314*57b5a4a6SAndroid Build Coastguard Worker        "{${it.toUByte().toString(16).padStart(2, '0').uppercase()}}"
1315*57b5a4a6SAndroid Build Coastguard Worker}
1316*57b5a4a6SAndroid Build Coastguard Worker-->
1317*57b5a4a6SAndroid Build Coastguard Worker
1318*57b5a4a6SAndroid Build Coastguard WorkerNow everything is ready to perform serialization of some byte arrays.
1319*57b5a4a6SAndroid Build Coastguard Worker
1320*57b5a4a6SAndroid Build Coastguard Worker```kotlin
1321*57b5a4a6SAndroid Build Coastguard Worker@Serializable
1322*57b5a4a6SAndroid Build Coastguard Workerdata class Project(val name: String, val attachment: ByteArray)
1323*57b5a4a6SAndroid Build Coastguard Worker
1324*57b5a4a6SAndroid Build Coastguard Workerfun main() {
1325*57b5a4a6SAndroid Build Coastguard Worker    val data = Project("kotlinx.serialization", byteArrayOf(0x0A, 0x0B, 0x0C, 0x0D))
1326*57b5a4a6SAndroid Build Coastguard Worker    val output = ByteArrayOutputStream()
1327*57b5a4a6SAndroid Build Coastguard Worker    encodeTo(DataOutputStream(output), data)
1328*57b5a4a6SAndroid Build Coastguard Worker    val bytes = output.toByteArray()
1329*57b5a4a6SAndroid Build Coastguard Worker    println(bytes.toAsciiHexString())
1330*57b5a4a6SAndroid Build Coastguard Worker    val input = ByteArrayInputStream(bytes)
1331*57b5a4a6SAndroid Build Coastguard Worker    val obj = decodeFrom<Project>(DataInputStream(input))
1332*57b5a4a6SAndroid Build Coastguard Worker    println(obj)
1333*57b5a4a6SAndroid Build Coastguard Worker}
1334*57b5a4a6SAndroid Build Coastguard Worker```
1335*57b5a4a6SAndroid Build Coastguard Worker
1336*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-formats-16.kt).
1337*57b5a4a6SAndroid Build Coastguard Worker
1338*57b5a4a6SAndroid Build Coastguard WorkerAs we can see, our custom byte array format is being used, with the compact encoding of its size in one byte.
1339*57b5a4a6SAndroid Build Coastguard Worker
1340*57b5a4a6SAndroid Build Coastguard Worker```text
1341*57b5a4a6SAndroid Build Coastguard Worker{00}{15}kotlinx.serialization{04}{0A}{0B}{0C}{0D}
1342*57b5a4a6SAndroid Build Coastguard WorkerProject(name=kotlinx.serialization, attachment=[10, 11, 12, 13])
1343*57b5a4a6SAndroid Build Coastguard Worker```
1344*57b5a4a6SAndroid Build Coastguard Worker
1345*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST -->
1346*57b5a4a6SAndroid Build Coastguard Worker
1347*57b5a4a6SAndroid Build Coastguard Worker---
1348*57b5a4a6SAndroid Build Coastguard Worker
1349*57b5a4a6SAndroid Build Coastguard WorkerThis chapter concludes [Kotlin Serialization Guide](serialization-guide.md).
1350*57b5a4a6SAndroid Build Coastguard Worker
1351*57b5a4a6SAndroid Build Coastguard Worker
1352*57b5a4a6SAndroid Build Coastguard Worker<!-- references -->
1353*57b5a4a6SAndroid Build Coastguard Worker[RFC 7049]: https://tools.ietf.org/html/rfc7049
1354*57b5a4a6SAndroid Build Coastguard Worker[IoT]: https://en.wikipedia.org/wiki/Internet_of_things
1355*57b5a4a6SAndroid Build Coastguard Worker[RFC 7049 Major Types]: https://tools.ietf.org/html/rfc7049#section-2.1
1356*57b5a4a6SAndroid Build Coastguard Worker
1357*57b5a4a6SAndroid Build Coastguard Worker<!-- Java references -->
1358*57b5a4a6SAndroid Build Coastguard Worker[java.io.DataOutput]: https://docs.oracle.com/javase/8/docs/api/java/io/DataOutput.html
1359*57b5a4a6SAndroid Build Coastguard Worker
1360*57b5a4a6SAndroid Build Coastguard Worker<!--- MODULE /kotlinx-serialization-core -->
1361*57b5a4a6SAndroid Build Coastguard Worker<!--- INDEX kotlinx-serialization-core/kotlinx.serialization -->
1362*57b5a4a6SAndroid Build Coastguard Worker
1363*57b5a4a6SAndroid Build Coastguard Worker[serializer]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/serializer.html
1364*57b5a4a6SAndroid Build Coastguard Worker[KSerializer]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-k-serializer/index.html
1365*57b5a4a6SAndroid Build Coastguard Worker
1366*57b5a4a6SAndroid Build Coastguard Worker<!--- INDEX kotlinx-serialization-core/kotlinx.serialization.builtins -->
1367*57b5a4a6SAndroid Build Coastguard Worker
1368*57b5a4a6SAndroid Build Coastguard Worker[kotlinx.serialization.builtins.ByteArraySerializer()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.builtins/-byte-array-serializer.html
1369*57b5a4a6SAndroid Build Coastguard Worker
1370*57b5a4a6SAndroid Build Coastguard Worker<!--- INDEX kotlinx-serialization-core/kotlinx.serialization.encoding -->
1371*57b5a4a6SAndroid Build Coastguard Worker
1372*57b5a4a6SAndroid Build Coastguard Worker[Encoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/index.html
1373*57b5a4a6SAndroid Build Coastguard Worker[Decoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/index.html
1374*57b5a4a6SAndroid Build Coastguard Worker[AbstractEncoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-abstract-encoder/index.html
1375*57b5a4a6SAndroid Build Coastguard Worker[AbstractDecoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-abstract-decoder/index.html
1376*57b5a4a6SAndroid Build Coastguard Worker[AbstractEncoder.encodeValue]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-abstract-encoder/encode-value.html
1377*57b5a4a6SAndroid Build Coastguard Worker[AbstractDecoder.decodeValue]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-abstract-decoder/decode-value.html
1378*57b5a4a6SAndroid Build Coastguard Worker[CompositeDecoder.decodeElementIndex]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/decode-element-index.html
1379*57b5a4a6SAndroid Build Coastguard Worker[Decoder.beginStructure]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/begin-structure.html
1380*57b5a4a6SAndroid Build Coastguard Worker[CompositeDecoder.decodeSequentially]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/decode-sequentially.html
1381*57b5a4a6SAndroid Build Coastguard Worker[Encoder.beginCollection]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/begin-collection.html
1382*57b5a4a6SAndroid Build Coastguard Worker[CompositeDecoder.decodeCollectionSize]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/decode-collection-size.html
1383*57b5a4a6SAndroid Build Coastguard Worker[Encoder.encodeNull]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/encode-null.html
1384*57b5a4a6SAndroid Build Coastguard Worker[Encoder.encodeNotNullMark]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/encode-not-null-mark.html
1385*57b5a4a6SAndroid Build Coastguard Worker[Decoder.decodeNotNullMark]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/decode-not-null-mark.html
1386*57b5a4a6SAndroid Build Coastguard Worker[Encoder.encodeSerializableValue]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/encode-serializable-value.html
1387*57b5a4a6SAndroid Build Coastguard Worker[Decoder.decodeSerializableValue]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/decode-serializable-value.html
1388*57b5a4a6SAndroid Build Coastguard Worker
1389*57b5a4a6SAndroid Build Coastguard Worker<!--- MODULE /kotlinx-serialization-properties -->
1390*57b5a4a6SAndroid Build Coastguard Worker<!--- INDEX kotlinx-serialization-properties/kotlinx.serialization.properties -->
1391*57b5a4a6SAndroid Build Coastguard Worker
1392*57b5a4a6SAndroid Build Coastguard Worker[kotlinx.serialization.properties.Properties]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-properties/kotlinx.serialization.properties/-properties/index.html
1393*57b5a4a6SAndroid Build Coastguard Worker
1394*57b5a4a6SAndroid Build Coastguard Worker<!--- MODULE /kotlinx-serialization-protobuf -->
1395*57b5a4a6SAndroid Build Coastguard Worker<!--- INDEX kotlinx-serialization-protobuf/kotlinx.serialization.protobuf -->
1396*57b5a4a6SAndroid Build Coastguard Worker
1397*57b5a4a6SAndroid Build Coastguard Worker[ProtoBuf]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-protobuf/kotlinx.serialization.protobuf/-proto-buf/index.html
1398*57b5a4a6SAndroid Build Coastguard Worker[ProtoBuf.encodeToByteArray]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-protobuf/kotlinx.serialization.protobuf/-proto-buf/encode-to-byte-array.html
1399*57b5a4a6SAndroid Build Coastguard Worker[ProtoBuf.decodeFromByteArray]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-protobuf/kotlinx.serialization.protobuf/-proto-buf/decode-from-byte-array.html
1400*57b5a4a6SAndroid Build Coastguard Worker[ProtoNumber]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-protobuf/kotlinx.serialization.protobuf/-proto-number/index.html
1401*57b5a4a6SAndroid Build Coastguard Worker[ProtoType]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-protobuf/kotlinx.serialization.protobuf/-proto-type/index.html
1402*57b5a4a6SAndroid Build Coastguard Worker[ProtoIntegerType]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-protobuf/kotlinx.serialization.protobuf/-proto-integer-type/index.html
1403*57b5a4a6SAndroid Build Coastguard Worker[ProtoIntegerType.DEFAULT]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-protobuf/kotlinx.serialization.protobuf/-proto-integer-type/-d-e-f-a-u-l-t/index.html
1404*57b5a4a6SAndroid Build Coastguard Worker[ProtoIntegerType.SIGNED]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-protobuf/kotlinx.serialization.protobuf/-proto-integer-type/-s-i-g-n-e-d/index.html
1405*57b5a4a6SAndroid Build Coastguard Worker[ProtoIntegerType.FIXED]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-protobuf/kotlinx.serialization.protobuf/-proto-integer-type/-f-i-x-e-d/index.html
1406*57b5a4a6SAndroid Build Coastguard Worker
1407*57b5a4a6SAndroid Build Coastguard Worker<!--- INDEX kotlinx-serialization-protobuf/kotlinx.serialization.protobuf.schema -->
1408*57b5a4a6SAndroid Build Coastguard Worker
1409*57b5a4a6SAndroid Build Coastguard Worker[ProtoBufSchemaGenerator]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-protobuf/kotlinx.serialization.protobuf.schema/-proto-buf-schema-generator/index.html
1410*57b5a4a6SAndroid Build Coastguard Worker
1411*57b5a4a6SAndroid Build Coastguard Worker<!--- MODULE /kotlinx-serialization-cbor -->
1412*57b5a4a6SAndroid Build Coastguard Worker<!--- INDEX kotlinx-serialization-cbor/kotlinx.serialization.cbor -->
1413*57b5a4a6SAndroid Build Coastguard Worker
1414*57b5a4a6SAndroid Build Coastguard Worker[Cbor]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor/index.html
1415*57b5a4a6SAndroid Build Coastguard Worker[Cbor.encodeToByteArray]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor/encode-to-byte-array.html
1416*57b5a4a6SAndroid Build Coastguard Worker[Cbor.decodeFromByteArray]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor/decode-from-byte-array.html
1417*57b5a4a6SAndroid Build Coastguard Worker[CborBuilder.ignoreUnknownKeys]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-cbor-builder/ignore-unknown-keys.html
1418*57b5a4a6SAndroid Build Coastguard Worker[ByteString]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-cbor/kotlinx.serialization.cbor/-byte-string/index.html
1419*57b5a4a6SAndroid Build Coastguard Worker
1420*57b5a4a6SAndroid Build Coastguard Worker<!--- END -->
1421