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] — 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] — returns the next value from the list. 646*57b5a4a6SAndroid Build Coastguard Worker* [decodeElementIndex][CompositeDecoder.decodeElementIndex] — 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] — 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