Kotlin Serialization ガイド　第3章 シリアライザ

#はじめに
　[Kotlin Serialization ガイドの目次](https://qiita.com/guijiu/items/097e858e4930b6d7e6c0)に基づいて「[Kotlin Serialization guide](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serialization-guide.md#kotlin-serialization-guide)」を訳しています。
　なお、翻訳には[DeepL](https://www.deepl.com/translator)の力を９９％借りています。
　もし、一緒に「[Kotlin Serialization ガイド](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serialization-guide.md#kotlin-serialization-guide)」の翻訳をして下さる方がいらっしゃいましたら、コメント欄などから連絡をください。

##第3章 シリアライザ ＜[原文](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md)＞
Latest commit 728e220 on 24 Nov 2020版

<!--- TEST_NAME SerializersTest -->

[Kotlin Serialization Guide](https://qiita.com/guijiu/items/097e858e4930b6d7e6c0)の第3章です。この章では、シリアライザについて詳しく見ていき、カスタムシリアライザの書き方を見ていきます。

**目次**

<!--- TOC -->

* [シリアライザの紹介](#シリアライザの紹介)
  * [プラグイン生成シリアライザ](#プラグイン生成シリアライザ)
  * [プラグイン生成ジェネリックシリアライザ](#プラグイン生成ジェネリックシリアライザ)
  * [組み込みプリミティブシリアライザ](#組み込みプリミティブシリアライザ)
  * [コレクションシリアライザを構築](#コレクションシリアライザを構築)
  * [トップレベルのシリアライザ機能を使用](#トップレベルシリアライザ機能を使用)
* [カスタムシリアライザ](#カスタムシリアライザ)
  * [プリミティブシリアライザ](#プリミティブシリアライザ)
  * [サロゲート経由のコンポジットシリアライザ](#サロゲート経由のコンポジットシリアライザ)
  * [手書き複合シリアライザ](#手書き複合シリアライザ)
  * [逐次復号化プロトコル（実験）](#逐次復号化プロトコル実験)
  * [サードパーティクラスのシリアライズ](#サードパーティクラスのシリアライズ)
  * [シリアライザを手動で渡す](#シリアライザを手動で渡す)
  * [プロパティにシリアライザを指定](#プロパティにシリアライザを指定)
  * [ファイルにシリアライザを指定](#ファイルにシリアライザを指定)
  * [ジェネリックタイプ用のカスタムシリアライザ](#ジェネリックタイプ用のカスタムシリアライザ)
  * [フォーマット固有のシリアライザ](#フォーマット固有のシリアライザ)
* [コンテクスチュアルシリアライズ](#コンテクスチュアルシリアライズ)
  * [シリアライザモジュール](#シリアライザモジュール)
* [他のKotlinクラスのための外部シリアライザの導出(実験)](#他のkotlinクラスのための外部シリアライザの導出実験)
  * [外部シリアライズはプロパティを使用](#外部シリアライズはプロパティを使用)

<!--- END -->

##シリアライザの紹介

　JSON のようなフォーマットでは、オブジェクトの特定の出力バイトへの _encoding_ を制御しますが、オブジェクトがどのように構成されたプロパティに分解されるかは _serializer_ によって制御されます。これまでは、[シリアライゼーション クラス](https://qiita.com/guijiu/items/4defa057b800a2348607#%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%BC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3-%E3%82%AF%E3%83%A9%E3%82%B9)で説明したように、[`@Serializable`](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serializable/index.html)アノテーションを使用して自動生成されたシリアライザを使用したり、[組み込みクラス](https://qiita.com/guijiu/items/036e9169cb6c6a73214f#組み込みクラス)で示した組み込みのシリアライザを使用したりしてきました。

　興味を与える例として、`rgb` バイトを格納した整数値を持つ以下の `Color` クラスを見てみよう。

<!--- 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))
}  
```              

> 完全なコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-01.kt)から取得できます。

　デフォルトでは、このクラスは `rgb` プロパティを JSON にシリアライズします。

```text
{"rgb":65280}
```     

<!--- TEST -->

###プラグイン生成シリアライザ

　前の例の `Color` クラスのように `@Serializable` アノテーションを付けたクラスはすべて、Kotlin Serialization コンパイラプラグインによって自動的に生成される [KSerializer] インターフェイスのインスタンスを取得します。

　シリアライズされたクラスの構造を記述した [descriptor][KSerializer.descriptor] プロパティを調べることができます。これについての詳細は次のセクションで説明します。

<!--- INCLUDE 
import kotlinx.serialization.*

@Serializable
@SerialName("Color")
class Color(val rgb: Int)
-->

```kotlin
fun main() {
    val colorSerializer: KSerializer<Color> = Color.serializer()
    println(colorSerializer.descriptor)
} 
```             

> 完全なコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-02.kt)から取得できます。

```text
Color(rgb: kotlin.Int)
```

<!--- TEST -->

　このシリアライザは、`Color` クラス自体がシリアライズされたとき、または他のクラスのプロパティとして使用されたときに、Kotlin Serialization フレームワークによって自動的に取得され、使用されます。

> シリアライズ可能なクラスのコンパニオンオブジェクトに対して独自の関数 `serializer()` を定義することはできません。


###プラグイン生成ジェネリックシリアライザ

　[ジェネリッククラス](https://qiita.com/guijiu/items/4defa057b800a2348607#%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AA%E3%83%83%E3%82%AF%E3%82%AF%E3%83%A9%E3%82%B9) で示した `Box` クラスのような汎用クラスの場合、自動的に生成される `.serializer()` 関数は対応するクラスの型パラメータの数だけパラメータを受け付ける。これらのパラメータは[KSerializer](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-k-serializer/index.html)型であるため、ジェネリッククラスのシリアライザのインスタンスを作成する際には、実際の型引数のシリアライザを指定しなければならない。

<!--- 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)
} 
```      

> 完全なコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-03.kt)から取得できます。                                                    

　ご覧の通り、具体的な `Box<Color>` をシリアライズするためにシリアライザがインスタンス化されています。

```text 
Box(contents: Color)
```       

<!--- TEST -->

###組み込みプリミティブシリアライザ

　[プリミティブ組み込みクラス](https://qiita.com/guijiu/items/036e9169cb6c6a73214f#%E3%83%97%E3%83%AA%E3%83%9F%E3%83%86%E3%82%A3%E3%83%96)のシリアライザは、`.serializer()`拡張子を使って取得することができます。

<!--- INCLUDE
import kotlinx.serialization.*
import kotlinx.serialization.builtins.*
-->

```kotlin 
fun main() {
    val intSerializer: KSerializer<Int> = Int.serializer()
    println(intSerializer.descriptor)
}
```

> フルコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-04.kt)から取得することができます。  

<!--- TEST 
PrimitiveDescriptor(kotlin.Int)
--> 

###コレクションシリアライザを構築

　[ビルトインコレクションシリアライザ](https://qiita.com/guijiu/items/036e9169cb6c6a73214f#%E3%83%AA%E3%82%B9%E3%83%88)は、必要に応じて、対応する関数[ListSerializer()]、[SetSerializer()]、[MapSerializer()]などを使って明示的に構築しなければなりません。これらのクラスは汎用的なので、シリアライザをインスタンス化するためには、対応する数の型パラメータに対応するシリアライザを提供しなければなりません。例えば、以下のように `List<String>` のシリアライザを生成することができます。

<!--- INCLUDE
import kotlinx.serialization.*
import kotlinx.serialization.builtins.*
-->

```kotlin 
fun main() {   
    val stringListSerializer: KSerializer<List<String>> = ListSerializer(String.serializer()) 
    println(stringListSerializer.descriptor)
}
```

> フルコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-05.kt)から取得することができます。 

<!--- TEST 
kotlin.collections.ArrayList(PrimitiveDescriptor(kotlin.String))
--> 

###トップレベルのシリアライザ機能を使用

　疑わしい場合は、トップレベルの汎用 `serializer<T>()`関数を使って、ソースコード中の任意のKotlin型のシリアライザを取得することができます。


<!--- 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)
}
```

> フルコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-06.kt)から取得することができます。 

<!--- TEST 
kotlin.collections.LinkedHashMap(PrimitiveDescriptor(kotlin.String), Color(rgb: kotlin.Int))
--> 

##カスタムシリアライザ

　プラグイン生成のシリアライザは便利だが、`Color` のようなクラスのために必要なJSONを生成できないかもしれない。代替案を検討してみましょう。


###プリミティブシリアライザ

　緑の色を `"00ff00"` で表現した16進文字列として `Color` クラスをシリアライズしたい。これを実現するために、`Color` クラスのための [KSerializer] インターフェースを実装したオブジェクトを書く。


<!--- 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))
    }
}
```

　シリアライザには3つの必要なピースがあります。

* [serialize](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serialization-strategy/serialize.html) 関数は、[SerializationStrategy](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serialization-strategy/index.html) を実装しています。  [Encoder](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/index.html) のインスタンスとシリアライズする値を受け取ります。  この関数は `Encoder` の `encodeXxx` 関数を使用して値をプリミティブのシーケンスとして表現します。シリアライズでサポートされるプリミティブの型ごとに `encodeXxx` がある。 この例では、[encodeString](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/encode-string.html)を使用しています。

* [deserialize](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-deserialization-strategy/deserialize.html) 関数は、[DeserializationStrategy](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-deserialization-strategy/index.html) を実装しています。 これは [Decoder](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/index.html) のインスタンスを受け取り、デシリアライズされた値を返します。これは `Decoder` の `decodeXxx` 関数を利用しますが、これは `Encoder` の対応する関数をミラーリングしたものです。 この例では、[decodeString](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/decode-string.html)が使われています。

* [descriptor](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-k-serializer/index.html#kotlinx.serialization%2FKSerializer%2Fdescriptor%2F%23%2FPointingToDeclaration%2F)プロパティは、`encodeXxx` と `decodeXxx` 関数がどのようなエンコーディング/デコーディングメソッドを呼び出すかをフォーマットの実装が事前に知っているように、正確に何をするのかを忠実に説明しなければなりません。いくつかのフォーマットでは、シリアライズされたデータのスキーマを生成するためにこれを使うこともあります。プリミティブシリアライズの場合、[PrimitiveSerialDescriptor](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.descriptors/-primitive-serial-descriptor.html)関数はシリアライズされる型のユニークな名前を指定して使用しなければならない。[PrimitiveKind](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.descriptors/-primitive-kind/index.html) は、実装で使用される特定の `encodeXxx`/`decodeXxx` メソッドを記述する。

> このように、`descriptor`がエンコード/デコード方法に対応していない場合、結果として得られるコードの振る舞いは不特定であり、将来の更新で任意に変更される可能性があります。       

　次のステップはシリアライザをクラスにバインドすることです。これは、[`with`](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serializable/index.html#kotlinx.serialization%2FSerializable%2Fwith%2F%23%2FPointingToDeclaration%2F)プロパティ値を追加することで、[`@Serializable`](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serializable/index.html)アノテーションで行います。

```kotlin
@Serializable(with = ColorAsStringSerializer::class)
class Color(val rgb: Int)
```  

　これで、先ほどと同じように `Color` クラスをシリアライズすることができるようになりました。

```kotlin
fun main() {
    val green = Color(0x00ff00)
    println(Json.encodeToString(green))
}  
```              

> 完全なコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-07.kt)から取得できます。

　シリアル表現を16進数の文字列として取得します。

```text
"00ff00"
```                        

<!--- TEST -->    

　デシリアライズも `deserialize` メソッドを実装しているので簡単である。

<!--- 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 
}  
```     

> フルコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-08.kt)から取得することができます。

<!--- TEST 
65280
-->

　また、`Color` プロパティを持つ別のクラスをシリアライズまたはデシリアライズしても動作します。

<!--- 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)
}  
```     

> フルコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-09.kt)から取得することができます。

　色`プロパティはいずれも文字列としてシリアライズされる。

```text 
{"background":"ffffff","foreground":"000000"}
```

<!--- TEST -->

###サロゲート経由のコンポジットシリアライザ

　さて、私たちの課題は `Color` をシリアライズして、JSON で `r`, `g`, `b` の 3 つのプロパティを持つクラスであるかのように JSON で表現し、JSON がオブジェクトとしてエンコードするようにすることです。これを実現する最も簡単な方法は、シリアル化に使用する `Color` を模倣した _surrogate_ クラスを定義することです。また、このサロゲートクラスの [SerialName] に `Color` を設定します。これで、この名前を使うフォーマットがあれば、サロゲートは `Color` クラスであるかのように見える。サロゲートクラスは `private` にすることができ、その `init` ブロックでクラスのシリアル表現に対するすべての制約を強制することができる。

```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)
    }
}
```

> クラス名を使用する場所の例は、ポリモーフィズムの章の[カスタムサブクラスシリアル名](https://qiita.com/guijiu/items/b177808b03b59f76c8ee#%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%82%B5%E3%83%96%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB%E5%90%8D)の項に記載されています。


　関数 `ColorSurrogate.serializer()` を使って、プラグインが生成したシリアライザを取得することができます。


　オリジナルの `Color` クラスのための [KSerializer](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-k-serializer/index.html) の実装は、`Color` と `ColorSurrogate` の変換を行う。しかし、実際のシリアライズロジックは `ColorSurrogate.serializer()` に委譲して [encodeSerializableValue](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/encode-serializable-value.html) と [decodeSerializableValue](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/decode-serializable-value.html) を使用し、サロゲート用に自動生成された [SerialDescriptor](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.descriptors/-serial-descriptor/index.html) を完全に再利用します。

```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)
    }
}
```

`ColorSerializer` シリアライザを `Color` クラスにバインドする。

```kotlin
@Serializable(with = ColorSerializer::class)
class Color(val rgb: Int)
```  

　これで、`Color` クラスのシリアライズの結果を楽しむことができる。


<!--- INCLUDE
fun main() {
    val green = Color(0x00ff00)
    println(Json.encodeToString(green))
}
-->

> フルコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-10.kt)から取得することができます。

```text
{"r":0,"g":255,"b":0}
```                        

<!--- TEST -->    

###手書き複合シリアライザ

　サロゲートソリューションが合わない場合もあります。おそらく、追加の割り当てによるパフォーマンスへの影響を避けたい場合や、結果として得られるシリアル表現のために、設定可能で動的なプロパティのセットが欲しい場合があるでしょう。このような場合は、生成されたシリアライザの動作を模倣するクラスシリアライザを手動で記述する必要があります。

```kotlin 
object ColorAsObjectSerializer : KSerializer<Color> {
```

　少しずつ紹介していきましょう。まず、[buildClassSerialDescriptor](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.descriptors/build-class-serial-descriptor.html)ビルダーを使って記述子を定義します。ビルダーDSLの[element](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.descriptors/-class-serial-descriptor-builder/element.html)関数は、対応するフィールドのシリアライザをタイプ別に自動的に取得します。要素の順序は重要です。これらの要素はゼロから始まるインデックスが付けられます。

```kotlin
    override val descriptor: SerialDescriptor =
        buildClassSerialDescriptor("Color") {
            element<Int>("r")
            element<Int>("g")
            element<Int>("b")
        }
```                                                                        

> ここでは「要素」は一般的な用語です。記述子の要素が何であるかは，その[SerialKind](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.descriptors/-serial-kind/index.html)に依存します。クラス記述子の要素はそのプロパティ、enum記述子の要素はそのケースなどです。

　次に、ブロック内の [CompositeEncoder](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-encoder/index.html) へのアクセスを提供する [encodeStructure](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/encode-structure.html) DSLを用いて `serialize` 関数を書く。[Encoder](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/index.html) と [CompositeEncoder](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-encoder/index.html) の違いは、後者には前者の `encodeXxx` 関数に対応する `encodeXxxElement` 関数があることである。これらの関数は記述子と同じ順番で呼ばれなければなりません。

```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)
        }
```                                     

　最も複雑なコードは `deserialize` 関数である。これはJSONのように、任意の順序でプロパティをデコードできるフォーマットをサポートしなければなりません。これは、[CompositeDecoder] へのアクセスを得るための [decodeStructure] の呼び出しから始まる。その中で、次の要素のインデックスをデコードするために [decodeElementIndex][CompositeDecoder.decodeElementIndex] を繰り返し呼び出すループを書き、次に、この例では [decodeIntElement][CompositeDecoder.decodeIntElement] を使って対応する要素をデコードし、最後に`CompositeDecoder.DECODE_DONE` が発生した。その中で、[decodeElementIndex][CompositeDecoder.decodeElementIndex]を繰り返し呼び出して次の要素のインデックスをデコードし、対応する要素を[decodeIntElement][CompositeDecoder.decodeIntElement]を使ってデコードし、最後に `CompositeDecoder.DECODE_DONE` に遭遇したときにループを終了させるループを書いています。


```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
}
-->

　ここで、できあがったシリアライザを `Color` クラスにバインドし、そのシリアライゼーション/デシリアライゼーションをテストする。

```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)
}  
```              

> フルコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-11.kt)から取得することができます。

　以前と同様に、`Color` クラスは 3 つのキーを持つ JSON オブジェクトとして表現されます。

```text
{"r":0,"g":255,"b":0}
```                        

<!--- TEST -->    

###逐次復号化プロトコル（実験）

　前節の `deserialize` 関数の実装は、どのような形式でも動作する。しかし、いくつかのフォーマットでは、すべての複雑なデータを常に順番に保存しているものと、時々しか保存していないものがあります(JSONは常にコレクションを順番に保存しています)。これらのフォーマットでは、ループ内で `decodeElementIndex` を呼び出す複雑なプロトコルは不要で、[CompositeDecoder.decodeSequentially](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/decode-sequentially.html) 関数が `true` を返す場合は、より高速な実装を使うことができます。 プラグインが生成するシリアライザは、実際には以下のコードと概念的に似ています。

<!--- 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)
}  
-->

> フルコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-12.kt)から取得することができます。

<!--- TEST
{"r":0,"g":255,"b":0}
--> 

###サードパーティクラスのシリアライズ

　時々、アプリケーションはシリアル化できない外部の型を使用しなければならないことがあります。例として、[java.util.Date]を使ってみましょう。先ほどと同様に、このクラスのために[KSerializer]の実装を書くことから始めます。私たちの目標は、[プリミティブシリアライザ](#プリミティブシリアライザ)のセクションのアプローチに従って、`Date`をLongのミリ秒数でシリアライズすることです。

> 以下の節では、どのような種類の `Date` シリアライザでも動作します。例えば、`Date` をオブジェクトとしてシリアライズしたい場合は、[サロゲートを使った複合シリアライザ](#サロゲート経由のコンポジットシリアライザ)のセクションのアプローチを使います。サードパーティの Kotlin クラスをシリアライズする必要がある場合は、[他のkotlinクラスのための外部シリアライザの導出(実験)](#他のkotlinクラスのための外部シリアライザの導出実験)も参照してください。

<!--- 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())
}
```

　Date` のソースコードを制御できないため、`DateAsLongSerializer` シリアライザを `Date` クラスに [@Serializable](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serializable/index.html) アノテーションでバインドすることはできません。これを回避する方法はいくつかあります。


###シリアライザを手動で渡す

　すべての `encodeToXxx` および `decodeFromXxx` 関数は、最初のシリアライザパラメータを持つオーバーロードを持っています。シリアライズ可能ではないクラス、例えば `Date` のような最上位クラスがシリアライズされる場合は、これらを使うことができます。

```kotlin
fun main() {                                              
    val kotlin10ReleaseDate = SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00") 
    println(Json.encodeToString(DateAsLongSerializer, kotlin10ReleaseDate))    
}
``` 

> フルコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-13.kt)から取得することができます。

```text
1.45549E+12
```     

<!--- TEST -->

###プロパティにシリアライザを指定

　Date`のようなシリアライズ可能ではないクラスのプロパティがシリアライズ可能なクラスの一部としてシリアライズされている場合、そのシリアライザを提供しなければなりません。これは、プロパティの [@Serializable](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serializable/index.html) アノテーションを使用して行います。

<!--- 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))
}
``` 

> フルコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-14.kt)から取得することができます。

　`stableReleaseDate`プロパティは、指定したシリアライゼーションの方針(the serialization strategy)でシリアライズされます。

```text
{"name":"Kotlin","stableReleaseDate":1455494400000}
```    

<!--- TEST -->

###ファイルにシリアライザを指定

　Date` のような特定の型のシリアライザは、ファイルの先頭にあるファイルレベルの[UseSerializers](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-use-serializers/index.html)アノテーションでソースコードファイル全体に対して指定することができます。

```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())
}
-->

　これで、追加のアノテーションなしに `Date` プロパティをシリアライズ可能なクラスで使用できるようになりました。

```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))
}
```

> フルコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-15.kt)から取得することができま。

```text
{"name":"Kotlin","stableReleaseDate":1455494400000}
```

<!--- TEST --> 

###ジェネリックタイプ用のカスタムシリアライザ

　以下に汎用の `Box<T>` クラスの例を見てみよう。これは、カスタムのシリアライズ戦略を持つ予定なので、`@Serializable(with = BoxSerializer::class)`とマークされている。

```kotlin       
@Serializable(with = BoxSerializer::class)
data class Box<T>(val contents: T) 
```                      

　この章の `Color` 型の例で見たように、通常の型に対する [KSerializer](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-k-serializer/index.html) の実装は `object` として書かれている。一般的なクラスのシリアライザは、その一般的なパラメータのためのシリアライザを使ってインスタンス化される。これについては[プラグインで生成された汎用シリアライザ](#プラグイン生成ジェネリックシリアライザ)のセクションで見た。ジェネリッククラス用のカスタムシリアライザは、その型が持つジェネリックパラメータの数だけ[KSerializer](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-k-serializer/index.html)パラメータを受け付けるコンストラクタを持つ `class` でなければならない。ここでは、`Box<T>` のシリアライザを書いてみましょう。

```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))
}
```

　これで、`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))
}
```

> フルコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-16.kt)から取得することができます。

　結果のJSONは `Project` クラスが直接シリアライズされたように見えます。

```text
{"name":"kotlinx.serialization"}
Box(contents=Project(name=kotlinx.serialization))
```     

<!--- TEST -->

###フォーマット固有のシリアライザ

　上記のカスタムシリアライザは、どのフォーマットでも同じように動作しました。しかし、シリアライザの実装で利用したいフォーマット固有の機能があるかもしれません。


* [Json](https://qiita.com/guijiu/items/9bcbe7379026d88978da#%E7%AC%AC%EF%BC%95%E7%AB%A0json%E3%81%AE%E6%A9%9F%E8%83%BD%E5%8E%9F%E6%96%87) の章の [Json transformations](https://qiita.com/guijiu/items/9bcbe7379026d88978da#json%E5%A4%89%E6%8F%9B) のセクションでは、JSON 固有の機能を利用したシリアライザの例を提供しています。


* フォーマットの実装では、[代替フォーマットとカスタムフォーマット(実験的)](https://qiita.com/guijiu/items/9a312d54b20baffff3bf#%E7%AC%AC%EF%BC%96%E7%AB%A0%E4%BB%A3%E6%9B%BF%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E3%81%A8%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E5%AE%9F%E9%A8%93)の章の[フォーマット固有の型](https://qiita.com/guijiu/items/9a312d54b20baffff3bf#%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E5%9B%BA%E6%9C%89%E3%81%AE%E5%9E%8B)のセクションで説明されているように、型に対してフォーマット固有の表現を持つことができます。 

　この章では、コンテキストに基づいてシリアライズ戦略を微調整するための一般的なアプローチを進めます。  

##コンテクスチュアルシリアライズ

　カスタムシリアライズ戦略を指定するこれまでのアプローチは、コンパイル時に完全に定義される _static_ でした。例外は[シリアライザを手動で渡す](#シリアライザを手動で渡す)というアプローチでしたが、トップレベルのオブジェクトに対してしか動作しませんでした。シリアライズされたオブジェクトツリーの奥にあるオブジェクトのシリアライズ戦略を実行時に変更する必要があるかもしれません。例えば、`java.util.Date`をJSON形式でISO 8601の文字列で表現したい場合と、データをシリアライズするプロトコルのバージョンに応じて長い整数で表現したい場合があります。これは_contextual_シリアライズと呼ばれ、組み込みの[ContextualSerializer]クラスでサポートされています。通常はこのシリアライザクラスを明示的に使う必要はありません。[Contextual]アノテーションは `@Serializable(with = ContextualSerializer::class)` アノテーションへのショートカットを提供し、[UseContextualSerialization]アノテーションは[UseSerializers]アノテーションと同様にファイルレベルで使用できます。前者を活用した例を見てみましょう。

<!--- 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))
}
-->    

　このクラスを実際にシリアライズするためには、`encodeToXxx`/decodeFromXxx` 関数を呼び出す際に対応するコンテキストを指定しなければなりません。これがないと、"Serializer for class 'Date' is not found" という例外が発生します。


> その例外を発生させる例については、[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-17.kt)を参照してください。

<!--- TEST LINES_START 
Exception in thread "main" kotlinx.serialization.SerializationException: Serializer for class 'Date' is not found.
Mark the class as @Serializable or provide the serializer explicitly.
-->

<!--- 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
)
-->

###シリアライザモジュール

　コンテキストを提供するために、実行時にどのシリアライザを使用してどのコンテキストでシリアライズ可能なクラスをシリアライズするかを記述する[SerializersModule](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module/index.html)インスタンスを定義します。これは、シリアライザを登録するための[SerializersModuleBuilder](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module-builder/index.html) DSLを提供する[SerializersModule {}](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module.html)ビルダー関数を使用して行います。以下の例では、シリアライザで[contextual](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/contextual.html)関数を使用しています。このシリアライザが定義されている対応するクラスは、reified type パラメータを介して自動的に取得されます。

```kotlin
private val module = SerializersModule { 
    contextual(DateAsLongSerializer)
}
``` 

　次に、[Json {}](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-json/kotlinx-serialization-json/kotlinx.serialization.json/-json/index.html)ビルダー関数と[serializersModule](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-json/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/index.html#kotlinx.serialization.json%2FJsonBuilder%2FserializersModule%2F%23%2FPointingToDeclaration%2F)プロパティを使用して、このモジュールで[Json](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-json/kotlinx-serialization-json/kotlinx.serialization.json/-json/index.html)フォーマットのインスタンスを作成します。


> カスタムJSON設定の詳細は、[JSON設定](https://qiita.com/guijiu/items/9bcbe7379026d88978da#json%E3%81%AE%E8%A8%AD%E5%AE%9A)のセクションに記載されています。


```kotlin           
val format = Json { serializersModule = module }
```

　これで、この `format` でデータをシリアライズすることができるようになりました。

```kotlin
fun main() {
    val data = ProgrammingLanguage("Kotlin", SimpleDateFormat("yyyy-MM-ddX").parse("2016-02-15+00"))
    println(format.encodeToString(data))
}
```

> フルコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-18.kt)から取得することができます。
```text
{"name":"Kotlin","stableReleaseDate":1455494400000}
```

<!--- TEST -->

> シリアライズモジュールの詳細は、[ポリモフィズム](https://qiita.com/guijiu/items/b177808b03b59f76c8ee#%E7%AC%AC4%E7%AB%A0%E3%83%9D%E3%83%AA%E3%83%A2%E3%83%95%E3%82%A3%E3%82%BA%E3%83%A0%E5%8E%9F%E6%96%87)の章の[ライブラリのシリアライザモジュールのマージ](https://qiita.com/guijiu/items/b177808b03b59f76c8ee#%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%81%AE%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%B6%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%81%AE%E3%83%9E%E3%83%BC%E3%82%B8)の項に記載されています。

##他のKotlinクラスのための外部シリアライザの導出(実験)

　シリアライズするサードパーティのクラスがプロパティのみのプライマリコンストラクタを持つKotlinクラスで、`@Serializable`のようなクラスであれば、[forClass`](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serializer/index.html#kotlinx.serialization%2FSerializer%2FforClass%2F%23%2FPointingToDeclaration%2F)プロパティを持つオブジェクトの[Serializer](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serializer/index.html)アノテーションを使って、_external_シリアライザを生成することができます。

```kotlin         
// NOT @Serializable
class Project(val name: String, val language: String)
                           
@Serializer(forClass = Project::class)
object ProjectSerializer
```

　この章で説明したアプローチのいずれかを使用して、このシリアライザをクラスにバインドする必要があります。この例では 「[シリアライザを手動で渡す](#シリアライザを手動で渡す)」のアプローチに従います。

```kotlin 
fun main() {
    val data = Project("kotlinx.serialization", "Kotlin")
    println(Json.encodeToString(ProjectSerializer, data))    
}
```          

> フルコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-19.kt)から取得することができます。

　これはすべての `Project` プロパティをシリアライズして取得する。


```text
{"name":"kotlinx.serialization","language":"Kotlin"}
```

###外部シリアライズはプロパティを使用

　"先ほど見たように、通常の `@Serializer` アノテーションはシリアライザを作成し、「[バッキングフィールドをシリアライズする](https://qiita.com/guijiu/items/4defa057b800a2348607#%E3%83%90%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%81%AF%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB%E5%8C%96%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99)」のようにしています。Serializer(forClass = ....)` を使った _External_シリアライズはバッキングフィールドにアクセスできず、動作が異なります。これは、セッターを持つ、あるいはプライマリコンストラクタの一部である _accessible_ プロパティのみをシリアライズします。 次の例はこれを示しています。"

```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))
}
```             

> フルコードは[こちら](https://github.com/Kotlin/kotlinx.serialization/blob/master/guide/example/example-serializer-20.kt)から取得することができます

　出力は以下のようになります。 

```text
{"name":"kotlinx.serialization","stars":9000}
```     

<!--- TEST -->

---

次の章では、[ポリモフィズム](https://qiita.com/guijiu/items/b177808b03b59f76c8ee#%E7%AC%AC4%E7%AB%A0%E3%83%9D%E3%83%AA%E3%83%A2%E3%83%95%E3%82%A3%E3%82%BA%E3%83%A0)を取り上げます。

<!-- 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://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serializable/index.html
[KSerializer]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-k-serializer/index.html
[KSerializer.descriptor]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-k-serializer/index.html#kotlinx.serialization%2FKSerializer%2Fdescriptor%2F%23%2FPointingToDeclaration%2F
[SerializationStrategy.serialize]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serialization-strategy/serialize.html
[SerializationStrategy]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serialization-strategy/index.html
[DeserializationStrategy.deserialize]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-deserialization-strategy/deserialize.html
[DeserializationStrategy]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-deserialization-strategy/index.html
[Serializable.with]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serializable/index.html#kotlinx.serialization%2FSerializable%2Fwith%2F%23%2FPointingToDeclaration%2F
[SerialName]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serial-name/index.html
[UseSerializers]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-use-serializers/index.html
[ContextualSerializer]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-contextual-serializer/index.html
[Contextual]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-contextual/index.html
[UseContextualSerialization]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-use-contextual-serialization/index.html
[Serializer]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serializer/index.html
[Serializer.forClass]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serializer/index.html#kotlinx.serialization%2FSerializer%2FforClass%2F%23%2FPointingToDeclaration%2F
<!--- INDEX kotlinx-serialization-core/kotlinx.serialization.builtins -->
[ListSerializer()]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.builtins/-list-serializer.html
[SetSerializer()]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.builtins/-set-serializer.html
[MapSerializer()]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.builtins/-map-serializer.html
<!--- INDEX kotlinx-serialization-core/kotlinx.serialization.encoding -->
[Encoder]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/index.html
[Encoder.encodeString]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/encode-string.html
[Decoder]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/index.html
[Decoder.decodeString]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/decode-string.html
[Encoder.encodeSerializableValue]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-encoder/encode-serializable-value.html
[Decoder.decodeSerializableValue]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-decoder/decode-serializable-value.html
[encodeStructure]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/encode-structure.html
[CompositeEncoder]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-encoder/index.html
[decodeStructure]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/decode-structure.html
[CompositeDecoder]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/index.html
[CompositeDecoder.decodeElementIndex]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/decode-element-index.html
[CompositeDecoder.decodeIntElement]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/decode-int-element.html
[CompositeDecoder.decodeSequentially]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.encoding/-composite-decoder/decode-sequentially.html
<!--- INDEX kotlinx-serialization-core/kotlinx.serialization.descriptors -->
[PrimitiveSerialDescriptor()]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.descriptors/-primitive-serial-descriptor.html
[PrimitiveKind]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.descriptors/-primitive-kind/index.html
[SerialDescriptor]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.descriptors/-serial-descriptor/index.html
[buildClassSerialDescriptor]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.descriptors/build-class-serial-descriptor.html
[ClassSerialDescriptorBuilder.element]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.descriptors/-class-serial-descriptor-builder/element.html
[SerialKind]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.descriptors/-serial-kind/index.html
<!--- INDEX kotlinx-serialization-core/kotlinx.serialization.modules -->
[SerializersModule]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module/index.html
[SerializersModule()]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module.html
[SerializersModuleBuilder]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module-builder/index.html
[_contextual]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/contextual.html
<!--- MODULE /kotlinx-serialization-json -->
<!--- INDEX kotlinx-serialization-json/kotlinx.serialization.json -->
[Json]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-json/kotlinx-serialization-json/kotlinx.serialization.json/-json/index.html
[Json()]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-json/kotlinx-serialization-json/kotlinx.serialization.json/-json.html
[JsonBuilder.serializersModule]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-json/kotlinx-serialization-json/kotlinx.serialization.json/-json-builder/index.html#kotlinx.serialization.json%2FJsonBuilder%2FserializersModule%2F%23%2FPointingToDeclaration%2F
<!--- END -->