| <!--- TEST_NAME SerializersTest --> |
| |
| # Serializers |
| |
| This is the third chapter of the [Kotlin Serialization Guide](serialization-guide.md). |
| In this chapter we'll take a look at serializers in more detail, and we'll see how custom serializers can be written. |
| |
| **Table of contents** |
| |
| <!--- TOC --> |
| |
| * [Introduction to serializers](#introduction-to-serializers) |
| * [Plugin-generated serializer](#plugin-generated-serializer) |
| * [Plugin-generated generic serializer](#plugin-generated-generic-serializer) |
| * [Builtin primitive serializers](#builtin-primitive-serializers) |
| * [Constructing collection serializers](#constructing-collection-serializers) |
| * [Using top-level serializer function](#using-top-level-serializer-function) |
| * [Custom serializers](#custom-serializers) |
| * [Primitive serializer](#primitive-serializer) |
| * [Delegating serializers](#delegating-serializers) |
| * [Composite serializer via surrogate](#composite-serializer-via-surrogate) |
| * [Hand-written composite serializer](#hand-written-composite-serializer) |
| * [Sequential decoding protocol (experimental)](#sequential-decoding-protocol-experimental) |
| * [Serializing 3rd party classes](#serializing-3rd-party-classes) |
| * [Passing a serializer manually](#passing-a-serializer-manually) |
| * [Specifying serializer on a property](#specifying-serializer-on-a-property) |
| * [Specifying serializer for a particular type](#specifying-serializer-for-a-particular-type) |
| * [Specifying serializers for a file](#specifying-serializers-for-a-file) |
| * [Specifying serializer globally using typealias](#specifying-serializer-globally-using-typealias) |
| * [Custom serializers for a generic type](#custom-serializers-for-a-generic-type) |
| * [Format-specific serializers](#format-specific-serializers) |
| * [Contextual serialization](#contextual-serialization) |
| * [Serializers module](#serializers-module) |
| * [Contextual serialization and generic classes](#contextual-serialization-and-generic-classes) |
| * [Deriving external serializer for another Kotlin class (experimental)](#deriving-external-serializer-for-another-kotlin-class-experimental) |
| * [External serialization uses properties](#external-serialization-uses-properties) |
| |
| <!--- END --> |
| |
| ## Introduction to serializers |
| |
| Formats, like JSON, control the _encoding_ of an object into specific output bytes, but how the object is decomposed |
| into its constituent properties is controlled by a _serializer_. So far we've been using automatically-derived |
| serializers by using the [`@Serializable`][Serializable] annotation as explained in |
| the [Serializable classes](/docs/basic-serialization.md#serializable-classes) section, or using builtin serializers that were shown in |
| the [Builtin classes](/docs/builtin-classes.md) section. |
| |
| As a motivating example, let us take the following `Color` class with an integer value storing its `rgb` bytes. |
| |
| <!--- INCLUDE |
| import kotlinx.serialization.* |
| import kotlinx.serialization.json.* |
| --> |
| |
| ```kotlin |
| @Serializable |
| class Color(val rgb: Int) |
| |
| fun main() { |
| val green = Color(0x00ff00) |
| println(Json.encodeToString(green)) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-01.kt). |
| |
| By default this class serializes its `rgb` property into JSON. |
| |
| ```text |
| {"rgb":65280} |
| ``` |
| |
| <!--- TEST --> |
| |
| ### Plugin-generated serializer |
| |
| Every class marked with the `@Serializable` annotation, like the `Color` class from the previous example, |
| gets an instance of the [KSerializer] interface automatically generated by the Kotlin Serialization compiler plugin. |
| We can retrieve this instance using the `.serializer()` function on the class's companion object. |
| |
| We can examine its [descriptor][KSerializer.descriptor] property that describes the structure of |
| the serialized class. We'll learn more details about that in the upcoming sections. |
| |
| <!--- INCLUDE |
| import kotlinx.serialization.* |
| |
| @Serializable |
| @SerialName("Color") |
| class Color(val rgb: Int) |
| --> |
| |
| ```kotlin |
| fun main() { |
| val colorSerializer: KSerializer<Color> = Color.serializer() |
| println(colorSerializer.descriptor) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-02.kt). |
| |
| ```text |
| Color(rgb: kotlin.Int) |
| ``` |
| |
| <!--- TEST --> |
| |
| This serializer is automatically retrieved and used by the Kotlin Serialization framework when the `Color` class |
| is itself serialized, or when it is used as a property of other classes. |
| |
| > You cannot define your own function `serializer()` on a companion object of a serializable class. |
| |
| ### Plugin-generated generic serializer |
| |
| For generic classes, like the `Box` class shown in the [Generic classes](basic-serialization.md#generic-classes) section, |
| the automatically generated `.serializer()` function accepts as many parameters as there are type parameters in the |
| corresponding class. These parameters are of type [KSerializer], so the actual type argument's serializer has |
| to be provided when constructing an instance of a serializer for a generic class. |
| |
| <!--- INCLUDE |
| import kotlinx.serialization.* |
| |
| @Serializable |
| @SerialName("Color") |
| class Color(val rgb: Int) |
| --> |
| |
| ```kotlin |
| @Serializable |
| @SerialName("Box") |
| class Box<T>(val contents: T) |
| |
| fun main() { |
| val boxedColorSerializer = Box.serializer(Color.serializer()) |
| println(boxedColorSerializer.descriptor) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-03.kt). |
| |
| As we can see, a serializer was instantiated to serialize a concrete `Box<Color>`. |
| |
| ```text |
| Box(contents: Color) |
| ``` |
| |
| <!--- TEST --> |
| |
| ### Builtin primitive serializers |
| |
| The serializers for the [primitive builtin classes](builtin-classes.md#primitives) can be retrieved |
| using `.serializer()` extensions. |
| |
| <!--- INCLUDE |
| import kotlinx.serialization.* |
| import kotlinx.serialization.builtins.* |
| --> |
| |
| ```kotlin |
| fun main() { |
| val intSerializer: KSerializer<Int> = Int.serializer() |
| println(intSerializer.descriptor) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-04.kt). |
| |
| <!--- TEST |
| PrimitiveDescriptor(kotlin.Int) |
| --> |
| |
| ### Constructing collection serializers |
| |
| [Builtin collection serializers](builtin-classes.md#lists), when needed, must be explicitly constructed |
| using the corresponding functions [ListSerializer()], [SetSerializer()], [MapSerializer()], etc. |
| These classes are generic, so to instantiate their serializer we must provide the serializers for the |
| corresponding number of their type parameters. |
| For example, we can produce a serializer for a `List<String>` in the following way. |
| |
| <!--- INCLUDE |
| import kotlinx.serialization.* |
| import kotlinx.serialization.builtins.* |
| --> |
| |
| ```kotlin |
| fun main() { |
| val stringListSerializer: KSerializer<List<String>> = ListSerializer(String.serializer()) |
| println(stringListSerializer.descriptor) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-05.kt). |
| |
| <!--- TEST |
| kotlin.collections.ArrayList(PrimitiveDescriptor(kotlin.String)) |
| --> |
| |
| ### Using top-level serializer function |
| |
| When in doubt, you can always use the top-level generic `serializer<T>()` |
| function to retrieve a serializer for an arbitrary Kotlin type in your source-code. |
| |
| <!--- INCLUDE |
| import kotlinx.serialization.* |
| --> |
| |
| ```kotlin |
| @Serializable |
| @SerialName("Color") |
| class Color(val rgb: Int) |
| |
| fun main() { |
| val stringToColorMapSerializer: KSerializer<Map<String, Color>> = serializer() |
| println(stringToColorMapSerializer.descriptor) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-06.kt). |
| |
| <!--- TEST |
| kotlin.collections.LinkedHashMap(PrimitiveDescriptor(kotlin.String), Color(rgb: kotlin.Int)) |
| --> |
| |
| ## Custom serializers |
| |
| A plugin-generated serializer is convenient, but it may not produce the JSON we want |
| for such a class as `Color`. Let's study alternatives. |
| |
| ### Primitive serializer |
| |
| We want to serialize the `Color` class as a hex string with the green color represented as `"00ff00"`. |
| To achieve this, we write an object that implements the [KSerializer] interface for the `Color` class. |
| |
| <!--- INCLUDE .*-serializer-.* |
| import kotlinx.serialization.* |
| import kotlinx.serialization.json.* |
| import kotlinx.serialization.encoding.* |
| import kotlinx.serialization.descriptors.* |
| --> |
| |
| ```kotlin |
| object ColorAsStringSerializer : KSerializer<Color> { |
| override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Color", PrimitiveKind.STRING) |
| |
| override fun serialize(encoder: Encoder, value: Color) { |
| val string = value.rgb.toString(16).padStart(6, '0') |
| encoder.encodeString(string) |
| } |
| |
| override fun deserialize(decoder: Decoder): Color { |
| val string = decoder.decodeString() |
| return Color(string.toInt(16)) |
| } |
| } |
| ``` |
| |
| Serializer has three required pieces. |
| |
| * The [serialize][SerializationStrategy.serialize] function implements [SerializationStrategy]. |
| It receives an instance of [Encoder] and a value to serialize. |
| It uses the `encodeXxx` functions of `Encoder` to represent a value as a sequence of primitives. There is an |
| `encodeXxx` for each primitive type supported by serialization. |
| In our example, [encodeString][Encoder.encodeString] is used. |
| |
| * The [deserialize][DeserializationStrategy.deserialize] function implements [DeserializationStrategy]. |
| It receives an instance of [Decoder] and returns a |
| deserialized value. It uses the `decodeXxx` functions of `Decoder`, which mirror the corresponding functions of `Encoder`. |
| In our example [decodeString][Decoder.decodeString] is used. |
| |
| * The [descriptor][KSerializer.descriptor] property must faithfully explain what exactly the `encodeXxx` and `decodeXxx` |
| functions do so that a format implementation knows in advance what encoding/decoding methods they call. |
| Some formats might also use it to generate a schema for the serialized data. For primitive serialization, |
| the [PrimitiveSerialDescriptor][PrimitiveSerialDescriptor()] function must be used with a unique name of the |
| type that is being serialized. |
| [PrimitiveKind] describes the specific `encodeXxx`/`decodeXxx` method that is being used in the implementation. |
| |
| > When the `descriptor` does not correspond to the encoding/decoding methods, then the behavior of the resulting code |
| > is unspecified, and may arbitrarily change in future updates. |
| |
| The next step is to bind a serializer to a class. This is done with the [`@Serializable`][Serializable] annotation by adding |
| the [`with`][Serializable.with] property value. |
| |
| ```kotlin |
| @Serializable(with = ColorAsStringSerializer::class) |
| class Color(val rgb: Int) |
| ``` |
| |
| Now we can serialize the `Color` class as we did before. |
| |
| ```kotlin |
| fun main() { |
| val green = Color(0x00ff00) |
| println(Json.encodeToString(green)) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-07.kt). |
| |
| We get the serial representation as the hex string we wanted. |
| |
| ```text |
| "00ff00" |
| ``` |
| |
| <!--- TEST --> |
| |
| Deserialization is also straightforward because we implemented the `deserialize` method. |
| |
| <!--- INCLUDE |
| object ColorAsStringSerializer : KSerializer<Color> { |
| override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Color", PrimitiveKind.STRING) |
| |
| override fun serialize(encoder: Encoder, value: Color) { |
| val string = value.rgb.toString(16).padStart(6, '0') |
| encoder.encodeString(string) |
| } |
| |
| override fun deserialize(decoder: Decoder): Color { |
| val string = decoder.decodeString() |
| return Color(string.toInt(16)) |
| } |
| } |
| --> |
| |
| ```kotlin |
| @Serializable(with = ColorAsStringSerializer::class) |
| class Color(val rgb: Int) |
| |
| fun main() { |
| val color = Json.decodeFromString<Color>("\"00ff00\"") |
| println(color.rgb) // prints 65280 |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-08.kt). |
| |
| <!--- TEST |
| 65280 |
| --> |
| |
| It also works if we serialize or deserialize a different class with `Color` properties. |
| |
| <!--- INCLUDE |
| object ColorAsStringSerializer : KSerializer<Color> { |
| override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Color", PrimitiveKind.STRING) |
| |
| override fun serialize(encoder: Encoder, value: Color) { |
| val string = value.rgb.toString(16).padStart(6, '0') |
| encoder.encodeString(string) |
| } |
| |
| override fun deserialize(decoder: Decoder): Color { |
| val string = decoder.decodeString() |
| return Color(string.toInt(16)) |
| } |
| } |
| --> |
| |
| ```kotlin |
| @Serializable(with = ColorAsStringSerializer::class) |
| data class Color(val rgb: Int) |
| |
| @Serializable |
| data class Settings(val background: Color, val foreground: Color) |
| |
| fun main() { |
| val data = Settings(Color(0xffffff), Color(0)) |
| val string = Json.encodeToString(data) |
| println(string) |
| require(Json.decodeFromString<Settings>(string) == data) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-09.kt). |
| |
| Both `Color` properties are serialized as strings. |
| |
| ```text |
| {"background":"ffffff","foreground":"000000"} |
| ``` |
| |
| <!--- TEST --> |
| |
| ### Delegating serializers |
| |
| In the previous example, we represented the `Color` class as a string. |
| String is considered to be a primitive type, therefore we used `PrimitiveClassDescriptor` and specialized `encodeString` method. |
| Now let's see what our actions would be if we have to serialize `Color` as another non-primitive type, let's say `IntArray`. |
| |
| An implementation of [KSerializer] for our original `Color` class is going to perform a conversion between |
| `Color` and `IntArray`, but delegate the actual serialization logic to the `IntArraySerializer` |
| using [encodeSerializableValue][Encoder.encodeSerializableValue] and |
| [decodeSerializableValue][Decoder.decodeSerializableValue]. |
| |
| ```kotlin |
| import kotlinx.serialization.builtins.IntArraySerializer |
| |
| class ColorIntArraySerializer : KSerializer<Color> { |
| private val delegateSerializer = IntArraySerializer() |
| override val descriptor = SerialDescriptor("Color", delegateSerializer.descriptor) |
| |
| override fun serialize(encoder: Encoder, value: Color) { |
| val data = intArrayOf( |
| (value.rgb shr 16) and 0xFF, |
| (value.rgb shr 8) and 0xFF, |
| value.rgb and 0xFF |
| ) |
| encoder.encodeSerializableValue(delegateSerializer, data) |
| } |
| |
| override fun deserialize(decoder: Decoder): Color { |
| val array = decoder.decodeSerializableValue(delegateSerializer) |
| return Color((array[0] shl 16) or (array[1] shl 8) or array[2]) |
| } |
| } |
| ``` |
| |
| Note that we can't use default `Color.serializer().descriptor` here because formats that rely |
| on the schema may think that we would call `encodeInt` instead of `encodeSerializableValue`. |
| Neither we can use `IntArraySerializer().descriptor` directly — otherwise, formats that handle int arrays specially |
| can't tell if `value` is really a `IntArray` or a `Color`. Don't worry, this optimization would still kick in |
| when serializing actual underlying int array. |
| |
| > Example of how format can treat arrays specially is shown in the [formats guide](formats.md#format-specific-types). |
| |
| Now we can use the serializer: |
| |
| ```kotlin |
| @Serializable(with = ColorIntArraySerializer::class) |
| class Color(val rgb: Int) |
| |
| fun main() { |
| val green = Color(0x00ff00) |
| println(Json.encodeToString(green)) |
| } |
| ``` |
| |
| As you can see, such array representation is not very useful in JSON, |
| but may save some space when used with a `ByteArray` and a binary format. |
| |
| > You can get the full code [here](../guide/example/example-serializer-10.kt). |
| |
| ```text |
| [0,255,0] |
| ``` |
| |
| <!--- TEST --> |
| |
| |
| ### Composite serializer via surrogate |
| |
| Now our challenge is to get `Color` serialized so that it is represented in JSON as if it is a class |
| with three properties—`r`, `g`, and `b`—so that JSON encodes it as an object. |
| The easiest way to achieve this is to define a _surrogate_ class mimicking the serialized form of `Color` that |
| we are going to use for its serialization. We also set the [SerialName] of this surrogate class to `Color`. Then if |
| any format uses this name the surrogate looks like it is a `Color` class. |
| The surrogate class can be `private`, and can enforce all the constraints on the serial representation |
| of the class in its `init` block. |
| |
| ```kotlin |
| @Serializable |
| @SerialName("Color") |
| private class ColorSurrogate(val r: Int, val g: Int, val b: Int) { |
| init { |
| require(r in 0..255 && g in 0..255 && b in 0..255) |
| } |
| } |
| ``` |
| |
| > An example of where the class name is used is shown in |
| > the [Custom subclass serial name](polymorphism.md#custom-subclass-serial-name) section in the chapter on polymorphism. |
| |
| Now we can use the `ColorSurrogate.serializer()` function to retrieve a plugin-generated serializer for the |
| surrogate class. |
| |
| We can use the same approach as in [delegating serializer](#delegating-serializers), but this time, |
| we are fully reusing an automatically |
| generated [SerialDescriptor] for the surrogate because it should be indistinguishable from the original. |
| |
| ```kotlin |
| object ColorSerializer : KSerializer<Color> { |
| override val descriptor: SerialDescriptor = ColorSurrogate.serializer().descriptor |
| |
| override fun serialize(encoder: Encoder, value: Color) { |
| val surrogate = ColorSurrogate((value.rgb shr 16) and 0xff, (value.rgb shr 8) and 0xff, value.rgb and 0xff) |
| encoder.encodeSerializableValue(ColorSurrogate.serializer(), surrogate) |
| } |
| |
| override fun deserialize(decoder: Decoder): Color { |
| val surrogate = decoder.decodeSerializableValue(ColorSurrogate.serializer()) |
| return Color((surrogate.r shl 16) or (surrogate.g shl 8) or surrogate.b) |
| } |
| } |
| ``` |
| |
| We bind the `ColorSerializer` serializer to the `Color` class. |
| |
| ```kotlin |
| @Serializable(with = ColorSerializer::class) |
| class Color(val rgb: Int) |
| ``` |
| |
| Now we can enjoy the result of serialization for the `Color` class. |
| |
| <!--- INCLUDE |
| fun main() { |
| val green = Color(0x00ff00) |
| println(Json.encodeToString(green)) |
| } |
| --> |
| |
| > You can get the full code [here](../guide/example/example-serializer-11.kt). |
| |
| ```text |
| {"r":0,"g":255,"b":0} |
| ``` |
| |
| <!--- TEST --> |
| |
| ### Hand-written composite serializer |
| |
| There are some cases where a surrogate solution does not fit. Perhaps we want to avoid the performance |
| implications of additional allocation, or we want a configurable/dynamic set of properties for the |
| resulting serial representation. In these cases we need to manually write a class |
| serializer which mimics the behaviour of a generated serializer. |
| |
| ```kotlin |
| object ColorAsObjectSerializer : KSerializer<Color> { |
| ``` |
| |
| Let's introduce it piece by piece. First, a descriptor is defined using the [buildClassSerialDescriptor] builder. |
| The [element][ClassSerialDescriptorBuilder.element] function in the builder DSL automatically fetches serializers |
| for the corresponding fields by their type. The order of elements is important. They are indexed starting from zero. |
| |
| ```kotlin |
| override val descriptor: SerialDescriptor = |
| buildClassSerialDescriptor("Color") { |
| element<Int>("r") |
| element<Int>("g") |
| element<Int>("b") |
| } |
| ``` |
| |
| > The "element" is a generic term here. What is an element of a descriptor depends on its [SerialKind]. |
| > Elements of a class descriptor are its properties, elements of a enum descriptor are its cases, etc. |
| |
| Then we write the `serialize` function using the [encodeStructure] DSL that provides access to |
| the [CompositeEncoder] in its block. The difference between [Encoder] and [CompositeEncoder] is the latter |
| has `encodeXxxElement` functions that correspond to the `encodeXxx` functions of the former. They must be called |
| in the same order as in the descriptor. |
| |
| ```kotlin |
| override fun serialize(encoder: Encoder, value: Color) = |
| encoder.encodeStructure(descriptor) { |
| encodeIntElement(descriptor, 0, (value.rgb shr 16) and 0xff) |
| encodeIntElement(descriptor, 1, (value.rgb shr 8) and 0xff) |
| encodeIntElement(descriptor, 2, value.rgb and 0xff) |
| } |
| ``` |
| |
| The most complex piece of code is the `deserialize` function. It must support formats, like JSON, that |
| can decode properties in an arbitrary order. It starts with the call to [decodeStructure] to |
| get access to a [CompositeDecoder]. Inside it we write a loop that repeatedly calls |
| [decodeElementIndex][CompositeDecoder.decodeElementIndex] to decode the index of the next element, then we decode the corresponding |
| element using [decodeIntElement][CompositeDecoder.decodeIntElement] in our example, and finally we terminate the loop when |
| `CompositeDecoder.DECODE_DONE` is encountered. |
| |
| ```kotlin |
| override fun deserialize(decoder: Decoder): Color = |
| decoder.decodeStructure(descriptor) { |
| var r = -1 |
| var g = -1 |
| var b = -1 |
| while (true) { |
| when (val index = decodeElementIndex(descriptor)) { |
| 0 -> r = decodeIntElement(descriptor, 0) |
| 1 -> g = decodeIntElement(descriptor, 1) |
| 2 -> b = decodeIntElement(descriptor, 2) |
| CompositeDecoder.DECODE_DONE -> break |
| else -> error("Unexpected index: $index") |
| } |
| } |
| require(r in 0..255 && g in 0..255 && b in 0..255) |
| Color((r shl 16) or (g shl 8) or b) |
| } |
| ``` |
| |
| <!--- INCLUDE |
| } |
| --> |
| |
| Now we bind the resulting serializer to the `Color` class and test its serialization/deserialization. |
| |
| ```kotlin |
| @Serializable(with = ColorAsObjectSerializer::class) |
| data class Color(val rgb: Int) |
| |
| fun main() { |
| val color = Color(0x00ff00) |
| val string = Json.encodeToString(color) |
| println(string) |
| require(Json.decodeFromString<Color>(string) == color) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-12.kt). |
| |
| As before, we got the `Color` class represented as a JSON object with three keys: |
| |
| ```text |
| {"r":0,"g":255,"b":0} |
| ``` |
| |
| <!--- TEST --> |
| |
| ### Sequential decoding protocol (experimental) |
| |
| The implementation of the `deserialize` function from the previous section works with any format. However, |
| some formats either always store all the complex data in order, or only do so sometimes (JSON always stores |
| collections in order). With these formats the complex protocol of calling `decodeElementIndex` in the loop is |
| not needed, and a faster implementation can be used if the [CompositeDecoder.decodeSequentially] function returns `true`. |
| The plugin-generated serializers are actually conceptually similar to the below code. |
| |
| <!--- INCLUDE |
| object ColorAsObjectSerializer : KSerializer<Color> { |
| |
| override val descriptor: SerialDescriptor = |
| buildClassSerialDescriptor("Color") { |
| element<Int>("r") |
| element<Int>("g") |
| element<Int>("b") |
| } |
| |
| override fun serialize(encoder: Encoder, value: Color) = |
| encoder.encodeStructure(descriptor) { |
| encodeIntElement(descriptor, 0, (value.rgb shr 16) and 0xff) |
| encodeIntElement(descriptor, 1, (value.rgb shr 8) and 0xff) |
| encodeIntElement(descriptor, 2, value.rgb and 0xff) |
| } |
| --> |
| |
| ```kotlin |
| override fun deserialize(decoder: Decoder): Color = |
| decoder.decodeStructure(descriptor) { |
| var r = -1 |
| var g = -1 |
| var b = -1 |
| if (decodeSequentially()) { // sequential decoding protocol |
| r = decodeIntElement(descriptor, 0) |
| g = decodeIntElement(descriptor, 1) |
| b = decodeIntElement(descriptor, 2) |
| } else while (true) { |
| when (val index = decodeElementIndex(descriptor)) { |
| 0 -> r = decodeIntElement(descriptor, 0) |
| 1 -> g = decodeIntElement(descriptor, 1) |
| 2 -> b = decodeIntElement(descriptor, 2) |
| CompositeDecoder.DECODE_DONE -> break |
| else -> error("Unexpected index: $index") |
| } |
| } |
| require(r in 0..255 && g in 0..255 && b in 0..255) |
| Color((r shl 16) or (g shl 8) or b) |
| } |
| ``` |
| |
| <!--- INCLUDE |
| } |
| |
| @Serializable(with = ColorAsObjectSerializer::class) |
| data class Color(val rgb: Int) |
| |
| fun main() { |
| val color = Color(0x00ff00) |
| val string = Json.encodeToString(color) |
| println(string) |
| require(Json.decodeFromString<Color>(string) == color) |
| } |
| --> |
| |
| > You can get the full code [here](../guide/example/example-serializer-13.kt). |
| |
| <!--- TEST |
| {"r":0,"g":255,"b":0} |
| --> |
| |
| ### Serializing 3rd party classes |
| |
| Sometimes an application has to work with an external type that is not serializable. |
| Let us use [java.util.Date] as an example. As before, we start by writing an implementation of [KSerializer] |
| for the class. Our goal is to get a `Date` serialized as a long number of milliseconds following the |
| approach from the [Primitive serializer](#primitive-serializer) section. |
| |
| > In the following sections any kind of `Date` serializer would work. For example, if we want `Date` to be serialized |
| > as an object, we would use an approach from |
| > the [Composite serializer via surrogate](#composite-serializer-via-surrogate) section. |
| > See also [Deriving external serializer for another Kotlin class (experimental)](#deriving-external-serializer-for-another-kotlin-class-experimental) |
| > when you need to serialize a 3rd-party Kotlin class that could have been serializable, but is not. |
| |
| <!--- INCLUDE |
| import java.util.Date |
| import java.text.SimpleDateFormat |
| --> |
| |
| ```kotlin |
| object DateAsLongSerializer : KSerializer<Date> { |
| override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG) |
| override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time) |
| override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong()) |
| } |
| ``` |
| |
| We cannot bind the `DateAsLongSerializer` serializer to the `Date` class with the [`@Serializable`][Serializable] annotation |
| because we don't control the `Date` source code. There are several ways to work around that. |
| |
| ### Passing a serializer manually |
| |
| All `encodeToXxx` and `decodeFromXxx` functions have an overload with the first serializer parameter. |
| When a non-serializable class, like `Date`, is the top-level class being serialized, we can use those. |
| |
| ```kotlin |
| fun main() { |
| val kotlin10ReleaseDate = SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00") |
| println(Json.encodeToString(DateAsLongSerializer, kotlin10ReleaseDate)) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-14.kt). |
| |
| ```text |
| 1455494400000 |
| ``` |
| |
| <!--- TEST --> |
| |
| ### Specifying serializer on a property |
| |
| When a property of a non-serializable class, like `Date`, is serialized as part of a serializable class we must supply |
| its serializer or the code will not compile. This is accomplished using the [`@Serializable`][Serializable] annotation on the property. |
| |
| <!--- INCLUDE |
| import java.util.Date |
| import java.text.SimpleDateFormat |
| |
| object DateAsLongSerializer : KSerializer<Date> { |
| override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG) |
| override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time) |
| override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong()) |
| } |
| --> |
| |
| ```kotlin |
| @Serializable |
| class ProgrammingLanguage( |
| val name: String, |
| @Serializable(with = DateAsLongSerializer::class) |
| val stableReleaseDate: Date |
| ) |
| |
| fun main() { |
| val data = ProgrammingLanguage("Kotlin", SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00")) |
| println(Json.encodeToString(data)) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-15.kt). |
| |
| The `stableReleaseDate` property is serialized with the serialization strategy that we specified for it: |
| |
| ```text |
| {"name":"Kotlin","stableReleaseDate":1455494400000} |
| ``` |
| |
| <!--- TEST --> |
| |
| ### Specifying serializer for a particular type |
| |
| [`@Serializable`][Serializable] annotation can also be applied directly to the types. |
| This is handy when a class that requires a custom serializer, such as `Date`, happens to be a generic type argument. |
| The most common use case for that is when you have a list of dates: |
| |
| <!--- INCLUDE |
| import java.util.Date |
| import java.text.SimpleDateFormat |
| |
| object DateAsLongSerializer : KSerializer<Date> { |
| override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG) |
| override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time) |
| override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong()) |
| } |
| --> |
| |
| ```kotlin |
| @Serializable |
| class ProgrammingLanguage( |
| val name: String, |
| val releaseDates: List<@Serializable(DateAsLongSerializer::class) Date> |
| ) |
| |
| fun main() { |
| val df = SimpleDateFormat("yyyy-MM-ddX") |
| val data = ProgrammingLanguage("Kotlin", listOf(df.parse("2023-07-06+00"), df.parse("2023-04-25+00"), df.parse("2022-12-28+00"))) |
| println(Json.encodeToString(data)) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-16.kt). |
| |
| ```text |
| {"name":"Kotlin","releaseDates":[1688601600000,1682380800000,1672185600000]} |
| ``` |
| |
| <!--- TEST --> |
| |
| ### Specifying serializers for a file |
| |
| A serializer for a specific type, like `Date`, can be specified for a whole source code file with the file-level |
| [UseSerializers] annotation at the beginning of the file. |
| |
| ```kotlin |
| @file:UseSerializers(DateAsLongSerializer::class) |
| ``` |
| |
| <!--- PREFIX --> |
| |
| <!--- INCLUDE |
| import java.util.Date |
| import java.text.SimpleDateFormat |
| |
| object DateAsLongSerializer : KSerializer<Date> { |
| override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG) |
| override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time) |
| override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong()) |
| } |
| --> |
| |
| Now a `Date` property can be used in a serializable class without additional annotations. |
| |
| ```kotlin |
| @Serializable |
| class ProgrammingLanguage(val name: String, val stableReleaseDate: Date) |
| |
| fun main() { |
| val data = ProgrammingLanguage("Kotlin", SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00")) |
| println(Json.encodeToString(data)) |
| } |
| ``` |
| > You can get the full code [here](../guide/example/example-serializer-17.kt). |
| |
| ```text |
| {"name":"Kotlin","stableReleaseDate":1455494400000} |
| ``` |
| |
| <!--- TEST --> |
| |
| ### Specifying serializer globally using typealias |
| |
| kotlinx.serialization tends to be the always-explicit framework when it comes to serialization strategies: normally, |
| they should be explicitly mentioned in `@Serializable` annotation. Therefore, we do not provide any kind of global serializer |
| configuration (except for [context serializer](#contextual-serialization) mentioned later). |
| |
| However, in projects with a large number of files and classes, it may be too cumbersome to specify `@file:UseSerializers` |
| every time, especially for classes like `Date` or `Instant` that have a fixed strategy of serialization across the project. |
| For such cases, it is possible to specify serializers using `typealias`es, as they preserve annotations, including serialization-related ones: |
| <!--- INCLUDE |
| import java.util.Date |
| import java.text.SimpleDateFormat |
| |
| object DateAsLongSerializer : KSerializer<Date> { |
| override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("DateAsLong", PrimitiveKind.LONG) |
| override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time) |
| override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong()) |
| } |
| |
| object DateAsSimpleTextSerializer: KSerializer<Date> { |
| override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("DateAsSimpleText", PrimitiveKind.LONG) |
| private val format = SimpleDateFormat("yyyy-MM-dd") |
| override fun serialize(encoder: Encoder, value: Date) = encoder.encodeString(format.format(value)) |
| override fun deserialize(decoder: Decoder): Date = format.parse(decoder.decodeString()) |
| } |
| --> |
| |
| ```kotlin |
| typealias DateAsLong = @Serializable(DateAsLongSerializer::class) Date |
| |
| typealias DateAsText = @Serializable(DateAsSimpleTextSerializer::class) Date |
| ``` |
| |
| Using these new different types, it is possible to serialize a Date differently without additional annotations: |
| |
| ```kotlin |
| @Serializable |
| class ProgrammingLanguage(val stableReleaseDate: DateAsText, val lastReleaseTimestamp: DateAsLong) |
| |
| fun main() { |
| val format = SimpleDateFormat("yyyy-MM-ddX") |
| val data = ProgrammingLanguage(format.parse("2016-02-15+00"), format.parse("2022-07-07+00")) |
| println(Json.encodeToString(data)) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-18.kt). |
| |
| ```text |
| {"stableReleaseDate":"2016-02-15","lastReleaseTimestamp":1657152000000} |
| ``` |
| |
| <!--- TEST --> |
| |
| ### Custom serializers for a generic type |
| |
| Let us take a look at the following example of the generic `Box<T>` class. |
| It is marked with `@Serializable(with = BoxSerializer::class)` as we plan to have a custom serialization |
| strategy for it. |
| |
| ```kotlin |
| @Serializable(with = BoxSerializer::class) |
| data class Box<T>(val contents: T) |
| ``` |
| |
| An implementation of [KSerializer] for a regular type is written as an `object`, as we saw in this chapter's |
| examples for the `Color` type. A generic class serializer is instantiated with serializers |
| for its generic parameters. We saw this in the [Plugin-generated generic serializer](#plugin-generated-generic-serializer) section. |
| A custom serializer for a generic class must be a `class` with a constructor that accepts as many [KSerializer] |
| parameters as the type has generic parameters. Let us write a `Box<T>` serializer that erases itself during |
| serialization, delegating everything to the underlying serializer of its `data` property. |
| |
| ```kotlin |
| class BoxSerializer<T>(private val dataSerializer: KSerializer<T>) : KSerializer<Box<T>> { |
| override val descriptor: SerialDescriptor = dataSerializer.descriptor |
| override fun serialize(encoder: Encoder, value: Box<T>) = dataSerializer.serialize(encoder, value.contents) |
| override fun deserialize(decoder: Decoder) = Box(dataSerializer.deserialize(decoder)) |
| } |
| ``` |
| |
| Now we can serialize and deserialize `Box<Project>`. |
| |
| ```kotlin |
| @Serializable |
| data class Project(val name: String) |
| |
| fun main() { |
| val box = Box(Project("kotlinx.serialization")) |
| val string = Json.encodeToString(box) |
| println(string) |
| println(Json.decodeFromString<Box<Project>>(string)) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-19.kt). |
| |
| The resulting JSON looks like the `Project` class was serialized directly. |
| |
| ```text |
| {"name":"kotlinx.serialization"} |
| Box(contents=Project(name=kotlinx.serialization)) |
| ``` |
| |
| <!--- TEST --> |
| |
| ### Format-specific serializers |
| |
| The above custom serializers worked in the same way for every format. However, there might be format-specific |
| features that a serializer implementation would like to take advantage of. |
| |
| * The [Json transformations](json.md#json-transformations) section of the [Json](json.md) chapter provides examples |
| of serializers that utilize JSON-specific features. |
| |
| * A format implementation can have a format-specific representation for a type as explained |
| in the [Format-specific types](formats.md#format-specific-types) section of |
| the [Alternative and custom formats (experimental)](formats.md) chapter. |
| |
| This chapter proceeds with a generic approach to tweaking the serialization strategy based on the context. |
| |
| ## Contextual serialization |
| |
| All the previous approaches to specifying custom serialization strategies were _static_, that is |
| fully defined at compile-time. The exception was the [Passing a serializer manually](#passing-a-serializer-manually) |
| approach, but it worked only on a top-level object. You might need to change the serialization |
| strategy for objects deep in the serialized object tree at run-time, with the strategy being selected in a context-dependent way. |
| For example, you might want to represent `java.util.Date` in JSON format as an ISO 8601 string or as a long integer |
| depending on a version of a protocol you are serializing data for. This is called _contextual_ serialization, and it |
| is supported by a built-in [ContextualSerializer] class. Usually we don't have to use this serializer class explicitly—there |
| is the [Contextual] annotation providing a shortcut to |
| the `@Serializable(with = ContextualSerializer::class)` annotation, |
| or the [UseContextualSerialization] annotation can be used at the file-level just like |
| the [UseSerializers] annotation. Let's see an example utilizing the former. |
| |
| <!--- INCLUDE |
| import java.util.Date |
| import java.text.SimpleDateFormat |
| --> |
| |
| ```kotlin |
| @Serializable |
| class ProgrammingLanguage( |
| val name: String, |
| @Contextual |
| val stableReleaseDate: Date |
| ) |
| ``` |
| |
| <!--- INCLUDE |
| |
| fun main() { |
| val data = ProgrammingLanguage("Kotlin", SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00")) |
| println(Json.encodeToString(data)) |
| } |
| --> |
| |
| To actually serialize this class we must provide the corresponding context when calling the `encodeToXxx`/`decodeFromXxx` |
| functions. Without it we'll get a "Serializer for class 'Date' is not found" exception. |
| |
| > See [here](../guide/example/example-serializer-20.kt) for an example that produces that exception. |
| |
| <!--- TEST LINES_START |
| Exception in thread "main" kotlinx.serialization.SerializationException: Serializer for class 'Date' is not found. |
| Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied. |
| --> |
| |
| <!--- INCLUDE |
| import kotlinx.serialization.modules.* |
| import java.util.Date |
| import java.text.SimpleDateFormat |
| |
| object DateAsLongSerializer : KSerializer<Date> { |
| override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG) |
| override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time) |
| override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong()) |
| } |
| |
| @Serializable |
| class ProgrammingLanguage( |
| val name: String, |
| @Contextual |
| val stableReleaseDate: Date |
| ) |
| --> |
| |
| ### Serializers module |
| |
| To provide a context, we define a [SerializersModule] instance that describes which serializers shall be used |
| at run-time to serialize which contextually-serializable classes. This is done using the |
| [SerializersModule {}][SerializersModule()] builder function, which provides the [SerializersModuleBuilder] DSL to |
| register serializers. In the below example we use the [contextual][_contextual] function with the serializer. The corresponding |
| class this serializer is defined for is fetched automatically via the `reified` type parameter. |
| |
| ```kotlin |
| private val module = SerializersModule { |
| contextual(DateAsLongSerializer) |
| } |
| ``` |
| |
| Next we create an instance of the [Json] format with this module using the |
| [Json {}][Json()] builder function and the [serializersModule][JsonBuilder.serializersModule] property. |
| |
| > Details on custom JSON configurations can be found in |
| > the [JSON configuration](json.md#json-configuration) section. |
| |
| ```kotlin |
| val format = Json { serializersModule = module } |
| ``` |
| |
| Now we can serialize our data with this `format`. |
| |
| ```kotlin |
| fun main() { |
| val data = ProgrammingLanguage("Kotlin", SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00")) |
| println(format.encodeToString(data)) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-21.kt). |
| ```text |
| {"name":"Kotlin","stableReleaseDate":1455494400000} |
| ``` |
| |
| <!--- TEST --> |
| |
| ### Contextual serialization and generic classes |
| |
| In the previous section we saw that we can register serializer instance in the module for a class we want to serialize contextually. |
| We also know that [serializers for generic classes have constructor parameters](#custom-serializers-for-a-generic-type) — type arguments serializers. |
| It means that we can't use one serializer instance for a class if this class is generic: |
| |
| ```kotlin |
| val incorrectModule = SerializersModule { |
| // Can serialize only Box<Int>, but not Box<String> or others |
| contextual(BoxSerializer(Int.serializer())) |
| } |
| ``` |
| |
| For cases when one want to serialize contextually a generic class, it is possible to register provider in the module: |
| |
| ```kotlin |
| val correctModule = SerializersModule { |
| // args[0] contains Int.serializer() or String.serializer(), depending on the usage |
| contextual(Box::class) { args -> BoxSerializer(args[0]) } |
| } |
| ``` |
| |
| <!--- CLEAR --> |
| |
| > Additional details on serialization modules are given in |
| > the [Merging library serializers modules](polymorphism.md#merging-library-serializers-modules) section of |
| > the [Polymorphism](polymorphism.md) chapter. |
| |
| ## Deriving external serializer for another Kotlin class (experimental) |
| |
| If a 3rd-party class to be serialized is a Kotlin class with a properties-only primary constructor, a kind of |
| class which could have been made `@Serializable`, then you can generate an _external_ serializer for it |
| using the [Serializer] annotation on an object with the [`forClass`][Serializer.forClass] property. |
| |
| ```kotlin |
| // NOT @Serializable |
| class Project(val name: String, val language: String) |
| |
| @Serializer(forClass = Project::class) |
| object ProjectSerializer |
| ``` |
| |
| You must bind this serializer to a class using one of the approaches explained in this chapter. We'll |
| follow the [Passing a serializer manually](#passing-a-serializer-manually) approach for this example. |
| |
| ```kotlin |
| fun main() { |
| val data = Project("kotlinx.serialization", "Kotlin") |
| println(Json.encodeToString(ProjectSerializer, data)) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-22.kt). |
| |
| This gets all the `Project` properties serialized: |
| |
| ```text |
| {"name":"kotlinx.serialization","language":"Kotlin"} |
| ``` |
| |
| <!--- TEST --> |
| |
| ### External serialization uses properties |
| |
| As we saw earlier, the regular `@Serializable` annotation creates a serializer so that |
| [Backing fields are serialized](basic-serialization.md#backing-fields-are-serialized). _External_ serialization using |
| `Serializer(forClass = ...)` has no access to backing fields and works differently. |
| It serializes only _accessible_ properties that have setters or are part of the primary constructor. |
| The following example shows this. |
| |
| ```kotlin |
| // NOT @Serializable, will use external serializer |
| class Project( |
| // val in a primary constructor -- serialized |
| val name: String |
| ) { |
| var stars: Int = 0 // property with getter & setter -- serialized |
| |
| val path: String // getter only -- not serialized |
| get() = "kotlin/$name" |
| |
| private var locked: Boolean = false // private, not accessible -- not serialized |
| } |
| |
| @Serializer(forClass = Project::class) |
| object ProjectSerializer |
| |
| fun main() { |
| val data = Project("kotlinx.serialization").apply { stars = 9000 } |
| println(Json.encodeToString(ProjectSerializer, data)) |
| } |
| ``` |
| |
| > You can get the full code [here](../guide/example/example-serializer-23.kt). |
| |
| The output is shown below. |
| |
| ```text |
| {"name":"kotlinx.serialization","stars":9000} |
| ``` |
| |
| <!--- TEST --> |
| |
| --- |
| |
| The next chapter covers [Polymorphism](polymorphism.md). |
| |
| <!-- Java references --> |
| [java.util.Date]: https://docs.oracle.com/javase/8/docs/api/java/util/Date.html |
| |
| <!--- MODULE /kotlinx-serialization-core --> |
| <!--- INDEX kotlinx-serialization-core/kotlinx.serialization --> |
| |
| [Serializable]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serializable/index.html |
| [KSerializer]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-k-serializer/index.html |
| [KSerializer.descriptor]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-k-serializer/descriptor.html |
| [SerializationStrategy.serialize]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serialization-strategy/serialize.html |
| [SerializationStrategy]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serialization-strategy/index.html |
| [DeserializationStrategy.deserialize]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-deserialization-strategy/deserialize.html |
| [DeserializationStrategy]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-deserialization-strategy/index.html |
| [Serializable.with]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serializable/with.html |
| [SerialName]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serial-name/index.html |
| [UseSerializers]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-use-serializers/index.html |
| [ContextualSerializer]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-contextual-serializer/index.html |
| [Contextual]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-contextual/index.html |
| [UseContextualSerialization]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-use-contextual-serialization/index.html |
| [Serializer]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serializer/index.html |
| [Serializer.forClass]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serializer/for-class.html |
| |
| <!--- INDEX kotlinx-serialization-core/kotlinx.serialization.builtins --> |
| |
| [ListSerializer()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.builtins/-list-serializer.html |
| [SetSerializer()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.builtins/-set-serializer.html |
| [MapSerializer()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.builtins/-map-serializer.html |
| |
| <!--- INDEX kotlinx-serialization-core/kotlinx.serialization.encoding --> |
| |
| [Encoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/index.html |
| [Encoder.encodeString]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/encode-string.html |
| [Decoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/index.html |
| [Decoder.decodeString]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/decode-string.html |
| [Encoder.encodeSerializableValue]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/encode-serializable-value.html |
| [Decoder.decodeSerializableValue]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/decode-serializable-value.html |
| [encodeStructure]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/encode-structure.html |
| [CompositeEncoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-encoder/index.html |
| [decodeStructure]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/decode-structure.html |
| [CompositeDecoder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/index.html |
| [CompositeDecoder.decodeElementIndex]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/decode-element-index.html |
| [CompositeDecoder.decodeIntElement]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/decode-int-element.html |
| [CompositeDecoder.decodeSequentially]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/decode-sequentially.html |
| |
| <!--- INDEX kotlinx-serialization-core/kotlinx.serialization.descriptors --> |
| |
| [PrimitiveSerialDescriptor()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.descriptors/-primitive-serial-descriptor.html |
| [PrimitiveKind]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.descriptors/-primitive-kind/index.html |
| [SerialDescriptor]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.descriptors/-serial-descriptor/index.html |
| [buildClassSerialDescriptor]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.descriptors/build-class-serial-descriptor.html |
| [ClassSerialDescriptorBuilder.element]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.descriptors/element.html |
| [SerialKind]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.descriptors/-serial-kind/index.html |
| |
| <!--- INDEX kotlinx-serialization-core/kotlinx.serialization.modules --> |
| |
| [SerializersModule]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module/index.html |
| [SerializersModule()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module.html |
| [SerializersModuleBuilder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module-builder/index.html |
| [_contextual]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/contextual.html |
| |
| <!--- MODULE /kotlinx-serialization-json --> |
| <!--- INDEX kotlinx-serialization-json/kotlinx.serialization.json --> |
| |
| [Json]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json/index.html |
| [Json()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json.html |
| [JsonBuilder.serializersModule]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/serializers-module.html |
| |
| <!--- END --> |
| |