Kotlin Serialization ガイド　第4章 ポリモフィズム

#はじめに
　[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)」の翻訳をして下さる方がいらっしゃいましたら、コメント欄などから連絡をください。

# 第4章　ポリモフィズム＜[原文](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#polymorphism)＞
<!--- TEST_NAME PolymorphismTest -->
Latest commit 728e220 on 24 Nov 2020版

　[Kotlinシリアライゼーションガイド](https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serialization-guide.md)の第4章です。

　この章では、Kotlin Serialization がどのように多態性クラスの階層を扱うかを見ていきます。

**Table of contents**

<!--- TOC -->

* [閉じたポリモフィズム](#閉じたポリモフィズム)
  * [静的な型](#静的な型)
  * [シリアライズ可能な階層の設計](#シリアライズ可能な階層の設計)
  * [シールドされたクラス](#シールドされたクラス)
  * [カスタムサブクラスのシリアル名](#カスタムサブクラスのシリアル名)
  * [基底クラスの具体的なプロパティ](#基底クラスの具体的なプロパティ)
  * [オブジェクト](#オブジェクト)
* [開かれたポリモフィズム](#開かれたポリモフィズム)
  * [登録されたサブクラス](#登録されたサブクラス)
  * [インターフェイスのシリアル化](#インターフェイスのシリアル化)
  * [インターフェース型のプロパティ](#インターフェース型のプロパティ)
  * [多態性のための静的親型検索](#多態性のための静的親型検索)
  * [多態クラスのプロパティを明示的にマーキング](#多態クラスのプロパティを明示的にマーキング)
  * [複数のスーパークラスの登録](#複数のスーパークラスの登録)
  * [多態性とジェネリッククラス](#多態性とジェネリッククラス)
  * [ライブラリのシリアライザモジュールのマージ](#ライブラリのシリアライザモジュールのマージ)
  * [デシリアライゼーションのためのデフォルトの多態型ハンドラ](#デシリアライゼーションのためのデフォルトの多態型ハンドラ)

<!--- END -->

<!--- INCLUDE .*-poly-.*
import kotlinx.serialization.*
import kotlinx.serialization.json.*
-->

## 閉じたポリモフィズム

　まずはポリモーフィズムの基本的な紹介から始めてみましょう。

### 静的な型

　Kotlin のシリアライズは default によって型に関して完全に静的なものになります。エンコードされたオブジェクトの構造は オブジェクトの *compile-time* 型によるものです。この側面をより詳しく調べて、どのように を使って多態データ構造をシリアライズします。

　Kotlin のシリアライズの静的な性質を示すために、以下のような設定をしてみましょう。`open class Project`には`name`のプロパティがあるだけで、その派生`class OwnedProject`には`owner`のプロパティが追加されています。以下の例では、実行時に`OwnedProject`のインスタンスで初期化される`Project`の静的型で`data`変数をシリアライズしています。

```kotlin
@Serializable
open class Project(val name: String)

class OwnedProject(name: String, val owner: String) : Project(name)

fun main() {
    val data: Project = OwnedProject("kotlinx.coroutines", "kotlin")
    println(Json.encodeToString(data))
}  
```                                

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

　`OwnedProject`のランタイムタイプにもかかわらず、`Project`クラスのプロパティだけがシリアライズされてしまいます。 

```text
{"name":"kotlinx.coroutines"}
```   

<!--- TEST -->                                                                    

　コンパイル時の `data` の型を `OwnedProject` に変更してみましょう。

```kotlin
@Serializable
open class Project(val name: String)
class OwnedProject(name: String, val owner: String) : Project(name)
fun main() {
    val data = OwnedProject("kotlinx.coroutines", "kotlin")
    println(Json.encodeToString(data))
}  
```                                

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

　`OwnedProject`クラスはシリアライズできないので、エラーが発生します。 

```text
Exception in thread "main" kotlinx.serialization.SerializationException: Serializer for class 'OwnedProject' is not found.
Mark the class as @Serializable or provide the serializer explicitly.
```                                                                       

<!--- TEST LINES_START -->

### シリアライズ可能な階層の設計

　先ほどの例の `OwnedProject` を単に `@Serializable` としてマークすることはできません。これはコンパイルされず、[コンストラクタのプロパティ要件](https://qiita.com/guijiu/items/4defa057b800a2348607#%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF%E3%81%AE%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E8%A6%81%E4%BB%B6)に陥ってしまいます。階層化されたクラスをシリアライズ可能にするには、親クラスのプロパティに `abstract` のマークを付けなければならず、`Project` クラスも `abstract` になってしまう。

```kotlin
@Serializable
abstract class Project {
    abstract val name: String
}

class OwnedProject(override val name: String, val owner: String) : Project()

fun main() {
    val data: Project = OwnedProject("kotlinx.coroutines", "kotlin")
    println(Json.encodeToString(data))
}  
```

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

　これは、シリアライズ可能なクラスの階層構造のための最良のデザインに近いですが、実行すると次のようなエラーが発生します。

```text 
Exception in thread "main" kotlinx.serialization.SerializationException: Class 'OwnedProject' is not registered for polymorphic serialization in the scope of 'Project'.
Mark the base class as 'sealed' or register the serializer explicitly.
```         

<!--- TEST LINES_START -->

### シールドされたクラス

　ポリモーフィック階層でシリアライズを利用する最も簡単な方法は、基底クラスに `sealed` をマークすることです。密閉されたクラスのすべてのサブクラスは、明示的に `@Serializable` としてマークしなければなりません。

```kotlin
@Serializable
sealed class Project {
    abstract val name: String
}
            
@Serializable
class OwnedProject(override val name: String, val owner: String) : Project()

fun main() {
    val data: Project = OwnedProject("kotlinx.coroutines", "kotlin")
    println(Json.encodeToString(data))
}  
```

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

　これで、JSONで多態性を表現するデフォルトの方法が見えてきました。結果のJSONオブジェクトには、`type`キーが_discriminator_として追加されます。 

```text 
{"type":"example.examplePoly04.OwnedProject","name":"kotlinx.coroutines","owner":"kotlin"}
```                  

<!--- TEST -->

### カスタムサブクラスのシリアル名

　type` キーの値は、デフォルトでは完全修飾されたクラス名である。これを変更するには、対応するクラスに [SerialName](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serial-name/index.html) アノテーションを付けることができます。

```kotlin
@Serializable
sealed class Project {
    abstract val name: String
}
            
@Serializable         
@SerialName("owned")
class OwnedProject(override val name: String, val owner: String) : Project()

fun main() {
    val data: Project = OwnedProject("kotlinx.coroutines", "kotlin")
    println(Json.encodeToString(data))
}  
```

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

　こうすることで、ソースコードのクラス名に影響されない安定した_serial name_を持つことができます。

```text 
{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}
```                   

<!--- TEST -->

> それに加えて、JSONではクラス判別器に別のキー名を使用するように設定することができます。[クラス判別器](https://qiita.com/guijiu/items/9bcbe7379026d88978da#%E3%82%AF%E3%83%A9%E3%82%B9%E5%88%A4%E5%88%A5%E5%99%A8)のセクションに例があります。

### 基底クラスの具体的なプロパティ

　シールドされた階層の基底クラスは、バッキングフィールドを持つプロパティを持つことができます。

```kotlin
@Serializable
sealed class Project {
    abstract val name: String   
    var status = "open"
}
            
@Serializable   
@SerialName("owned")
class OwnedProject(override val name: String, val owner: String) : Project()

fun main() {
    val json = Json { encodeDefaults = true } // "status" will be skipped otherwise
    val data: Project = OwnedProject("kotlinx.coroutines", "kotlin")
    println(json.encodeToString(data))
}  
```

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

　スーパークラスのプロパティは、サブクラスのプロパティの前にシリアライズされます。

```text 
{"type":"owned","status":"open","name":"kotlinx.coroutines","owner":"kotlin"}
```                                                                                  

<!--- TEST -->

### オブジェクト

　封印された階層はサブクラスとしてオブジェクトを持つことができ、`@Serializable`としてマークされている必要があります。ここでは、`Response` クラスの階層を持つ別の例を見てみましょう。

```kotlin
@Serializable
sealed class Response
                      
@Serializable
object EmptyResponse : Response()

@Serializable   
class TextResponse(val text: String) : Response()   
```

　さまざまなレスポンスのリストをシリアライズしてみましょう。

```kotlin
fun main() {
    val list = listOf(EmptyResponse, TextResponse("OK"))
    println(Json.encodeToString(list))
}  
```

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

　オブジェクトは空のクラスとしてシリアライズされ、デフォルトでは完全修飾されたクラス名を型として使用します。

```text 
[{"type":"example.examplePoly07.EmptyResponse"},{"type":"example.examplePoly07.TextResponse","text":"OK"}]
```                            

<!--- TEST -->

> オブジェクトがプロパティを持っていてもシリアル化されません。

## 開かれたポリモフィズム

　シリアライズは任意の `open` クラスや `abstract` クラスで動作します。しかし、この種の多態性はオープンであるため、ソースコードのどこにでもサブクラスが定義されている可能性があり、他のモジュールであっても、シリアライズされるサブクラスのリストはコンパイル時に決定できず、実行時に明示的に登録しなければなりません。

### 登録されたサブクラス
　まずは、[シリアライズ可能な階層の設計](#シリアライズ可能な階層の設計)のセクションのコードから見ていきましょう。封印せずにシリアライズで動作させるためには、[SerializersModule {}](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module.html)ビルダー関数を使って[SerializersModule](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module/index.html)を定義する必要があります。モジュールでは、[ポリモーフィック](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/polymorphic.html)ビルダーで基底クラスを指定し、各サブクラスを[サブクラス](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/subclass.html)関数で登録します。これで、カスタム JSON 設定をこのモジュールでインスタンス化し、シリアライズに使用できるようになりました。

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

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

```kotlin 
val module = SerializersModule {
    polymorphic(Project::class) {
        subclass(OwnedProject::class)
    }
}

val format = Json { serializersModule = module }

@Serializable
abstract class Project {
    abstract val name: String
}
            
@Serializable
@SerialName("owned")
class OwnedProject(override val name: String, val owner: String) : Project()

fun main() {
    val data: Project = OwnedProject("kotlinx.coroutines", "kotlin")
    println(format.encodeToString(data))
}    
```

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

　この追加設定により、[シールドされたクラス](#シールドされたクラス) セクションの密閉されたクラスと同じように動作しますが、ここではサブクラスをコード全体に任意に分散させることができます。

```text 
{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}
```                  

<!--- TEST -->
>この例は `serializer` 関数の制限のため JVM でしか動作しないことに注意してください。JSやNativeの場合は、明示的なシリアライザ`format.encodeToString(PolymorphicSerializer(Project::class), data)`を使用する必要があります。この問題については、[ここら](https://github.com/Kotlin/kotlinx.serialization/issues/1077)で追跡することができます。

### インターフェイスのシリアル化 

 先ほどの例を更新して、`Project` スーパークラスをインターフェイスにすることができる。 しかし、インターフェイスそのものを `@Serializable` としてマークすることはできない。問題ない。インターフェースはそれ自体でインスタンスを持つことはできない。 インターフェースはその派生クラスのインスタンスでしか表現できない。インターフェースはKotlin言語ではポリモーフィズムを可能にするために使われているので、すべてのインターフェースは[PolymorphicSerializer](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-polymorphic-serializer/index.html)ストラテジーを使って暗黙のうちに直列化可能であるとみなされます。これらの実装クラスを `@Serializable` としてマークして登録するだけです。

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

val module = SerializersModule {
    polymorphic(Project::class) {
        subclass(OwnedProject::class)
    }
}

val format = Json { serializersModule = module }
--> 

```kotlin 
interface Project {
    val name: String
}

@Serializable
@SerialName("owned")
class OwnedProject(override val name: String, val owner: String) : Project
```

　これで、`data` を `Project` 型で宣言すると、以前と同様に `format.encodeToString` を呼び出すことができるようになりました。

```kotlin
fun main() {
    val data: Project = OwnedProject("kotlinx.coroutines", "kotlin")
    println(format.encodeToString(data))
}    
```

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

```text 
{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}
```

<!--- TEST LINES_START -->

### インターフェース型のプロパティ

　先ほどの例に引き続き、`Project` インターフェースを他のシリアライズ可能なクラスのプロパティとして使うとどうなるか見てみましょう。インターフェースは暗黙のうちに多態性を持っているので、インターフェース型のプロパティを宣言すればいいのです。


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

val module = SerializersModule {
    polymorphic(Project::class) {
        subclass(OwnedProject::class)
    }
}

val format = Json { serializersModule = module }

interface Project {
    val name: String
}

@Serializable
@SerialName("owned")
class OwnedProject(override val name: String, val owner: String) : Project
-->

```kotlin
@Serializable
class Data(val project: Project) // Project is an interface

fun main() {
    val data = Data(OwnedProject("kotlinx.coroutines", "kotlin"))
    println(format.encodeToString(data))
}        
```

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

　`format`の[SerializersModule](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module/index.html)にシリアライズされるインターフェースの実際のサブタイプを登録しておけば、実行時に動作するようになる。

```text 
{"project":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}}
```

<!--- TEST --> 

### 多態性のための静的親型検索

　多態性クラスのシリアライズの際には、多態性階層のルート型 (この例では `Project`) が静的に決定されます。ここでは直列化可能な `抽象クラス Project` を例にとりますが、`main` 関数を変更して `data` の型が `Any` であることを宣言します。

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

val module = SerializersModule {
    polymorphic(Project::class) {
        subclass(OwnedProject::class)
    }
}

val format = Json { serializersModule = module }

@Serializable
abstract class Project {
    abstract val name: String
}
            
@Serializable
@SerialName("owned")
class OwnedProject(override val name: String, val owner: String) : Project()
--> 

```kotlin 
fun main() {
    val data: Any = OwnedProject("kotlinx.coroutines", "kotlin")
    println(format.encodeToString(data))
}    
```

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

　以下のような例外が発生します。

```text
Exception in thread "main" kotlinx.serialization.SerializationException: Serializer for class 'Any' is not found.
Mark the class as @Serializable or provide the serializer explicitly.
```

<!--- TEST LINES_START -->

　ソースコードで使用している対応するスタティック型を重視して、ポリモーフィックシリアライズのためのクラスを登録しなければなりません。まず、`Any`のサブクラスを登録するようにモジュールを変更します。

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

```kotlin
val module = SerializersModule {
    polymorphic(Any::class) {
        subclass(OwnedProject::class)
    }
}
```                                                                                    

<!--- INCLUDE 
val format = Json { serializersModule = module }

@Serializable
abstract class Project {
    abstract val name: String
}
            
@Serializable
@SerialName("owned")
class OwnedProject(override val name: String, val owner: String) : Project()
-->

　そこでは、`Any`型の変数をシリアライズしてみる。

```kotlin
fun main() {
    val data: Any = OwnedProject("kotlinx.coroutines", "kotlin")
    println(format.encodeToString(data))
}    
```

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

　しかし、`Any`はクラスであり、シリアライズはできません。

```text 
Exception in thread "main" kotlinx.serialization.SerializationException: Serializer for class 'Any' is not found.
Mark the class as @Serializable or provide the serializer explicitly.
```

<!--- TEST LINES_START -->

　基底クラス `Any` の [PolymorphicSerializer] のインスタンスを明示的に [encodeToString][Json.encodeToString] 関数の最初のパラメータとして渡さなければなりません。

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

val module = SerializersModule {
    polymorphic(Any::class) {
        subclass(OwnedProject::class)
    }
}

val format = Json { serializersModule = module }

@Serializable
abstract class Project {
    abstract val name: String
}
            
@Serializable
@SerialName("owned")
class OwnedProject(override val name: String, val owner: String) : Project()
-->

```kotlin
fun main() {
    val data: Any = OwnedProject("kotlinx.coroutines", "kotlin")
    println(format.encodeToString(PolymorphicSerializer(Any::class), data))
}    
```

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

　明示的なシリアライザを使用すると、以前と同じように動作します。

```text 
{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}
```                  

<!--- TEST -->

### 多態クラスのプロパティを明示的にマーキング

　インターフェースはすべて実行時のポリモーフィズムに関するものなので、インターフェース型のプロパティは暗黙のうちにポリモーフィズムとみなされます。しかし、Kotlinのシリアライズでは、シリアライズ可能なクラスの型がシリアライズ不可能なプロパティを持つクラスをコンパイルしません。もし `Any` クラスやその他のシリアライズ可能でないクラスのプロパティを持っている場合は、[プロパティにシリアライザを指定](https://qiita.com/guijiu/items/be7fa14c49cb7e3006dd#%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%81%AB%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%B6%E3%82%92%E6%8C%87%E5%AE%9A)のセクションで見たように、[`@Serializable`][Serializable]アノテーションを使って明示的にそのシリアライズ方法を提供しなければなりません。プロパティの多態直列化戦略を指定するには、特殊目的の [`@Polymorphic`][Polymorphic] アノテーションを使用します。

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

val module = SerializersModule {
    polymorphic(Any::class) {
        subclass(OwnedProject::class)
    }
}

val format = Json { serializersModule = module }

interface Project {
    val name: String
}

@Serializable
@SerialName("owned")
class OwnedProject(override val name: String, val owner: String) : Project
-->

```kotlin
@Serializable
class Data(
    @Polymorphic // the code does not compile without it 
    val project: Any 
)

fun main() {
    val data = Data(OwnedProject("kotlinx.coroutines", "kotlin"))
    println(format.encodeToString(data))
}
```

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

<!--- TEST 
{"project":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}}
-->

### 複数のスーパークラスの登録

　同じクラスがスーパークラスのリストからコンパイル時の型が異なるプロパティの値としてシリアライズされる場合は、スーパークラスごとに個別に[SerializersModule]に登録する必要があります。全てのサブクラスの登録を別の関数に抽出して、スーパークラスごとに使うと便利です。以下のようなテンプレートで記述します。

<!--- INCLUDE 
import kotlinx.serialization.modules.*
import kotlin.reflect.KClass
-->

```kotlin
val module = SerializersModule {
    fun PolymorphicModuleBuilder<Project>.registerProjectSubclasses() {
        subclass(OwnedProject::class)
    }
    polymorphic(Any::class) { registerProjectSubclasses() }
    polymorphic(Project::class) { registerProjectSubclasses() }
}        
```

<!--- INCLUDE

val format = Json { serializersModule = module }

interface Project {
    val name: String
}

@Serializable
@SerialName("owned")
class OwnedProject(override val name: String, val owner: String) : Project

@Serializable
class Data(
    val project: Project,
    @Polymorphic val any: Any 
)

fun main() {
    val project = OwnedProject("kotlinx.coroutines", "kotlin")
    val data = Data(project, project)
    println(format.encodeToString(data))
}        
-->

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

<!--- TEST 
{"project":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"},"any":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}}
-->

### 多態性とジェネリッククラス

　シリアライズ可能なクラスの汎用サブタイプは、特別な処理を必要とします。以下の階層を考えてみましょう。

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

```kotlin 
@Serializable
abstract class Response<out T>
            
@Serializable
@SerialName("OkResponse")
data class OkResponse<out T>(val data: T) : Response<T>()
```

　Kotlinのシリアライズには、多態型 `OkResponse<T>` のプロパティをシリアライズする際に、型パラメータ `T` に対して実際に提供される引数の型を表現するためのストラテジーが組み込まれていません。このストラテジーは、`Response`用のシリアライザモジュールを定義する際に明示的に指定する必要があります。以下の例では、`OkResponse.serializer(....)`を使って `OkResponse` クラスの [プラグイン生成ジェネリックシリアライザ](https://qiita.com/guijiu/items/be7fa14c49cb7e3006dd#%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E7%94%9F%E6%88%90%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AA%E3%83%83%E3%82%AF%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%B6) を作成し、`Any` クラスをベースにして [PolymorphicSerializer] (https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-polymorphic-serializer/index.html) インスタンスを作成します。これにより、`OkResponse`のインスタンスを、`Any`のサブタイプとしてポリモーフィックに登録された任意の`data`プロパティでシリアライズすることができます。

```kotlin   
val responseModule = SerializersModule {
    polymorphic(Response::class) {
        subclass(OkResponse.serializer(PolymorphicSerializer(Any::class)))
    }
}
```

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

　アプリケーションのサイズが大きくなり、ソースコードモジュールに分割された場合、1つのシリアライザモジュールにすべてのクラス階層を格納するのは不便になるかもしれません。前節のコードに`Project`階層を持つライブラリを追加してみよう。

```kotlin
val projectModule = SerializersModule {
    fun PolymorphicModuleBuilder<Project>.registerProjectSubclasses() {
        subclass(OwnedProject::class)
    }
    polymorphic(Any::class) { registerProjectSubclasses() }
    polymorphic(Project::class) { registerProjectSubclasses() }
}
```

<!--- INCLUDE

@Serializable
abstract class Project {
    abstract val name: String
}
            
@Serializable
@SerialName("OwnedProject")
data class OwnedProject(override val name: String, val owner: String) : Project()
-->

[plus]演算子を使ってこれら2つのモジュールを結合することで、同じ[Json]形式のインスタンスで両方のモジュールを使用することができます。

> [SerializersModule {}][SerializersModule()] DSL の [include][SerializersModuleBuilder.include] 関数を使用することもできます。


```kotlin
val format = Json { serializersModule = projectModule + responseModule }
````                                                                  

　これで、両方の階層のクラスを一緒にシリアライズし、一緒にデシリアライズすることができるようになりました。

```kotlin 
fun main() {
    // both Response and Project are abstract and their concrete subtypes are being serialized
    val data: Response<Project> =  OkResponse(OwnedProject("kotlinx.serialization", "kotlin"))
    val string = format.encodeToString(data)
    println(string)
    println(format.decodeFromString<Response<Project>>(string))
}

```

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

生成されているJSONは深いポリモーフィックを持っています。

```text
{"type":"OkResponse","data":{"type":"OwnedProject","name":"kotlinx.serialization","owner":"kotlin"}}
OkResponse(data=OwnedProject(name=kotlinx.serialization, owner=kotlin))
```

<!--- TEST -->

　抽象クラスとそれのいくつかの実装を持つライブラリや共有モジュールを書いている場合、クライアントが自分のモジュールと自分のモジュールを組み合わせることができるように、クライアントが使用できるように自分のシリアライザモジュールを公開することができます。

### デシリアライゼーションのためのデフォルトの多態型ハンドラ

　登録されていなかったサブクラスをデシリアライズすると、どうなるのでしょうか？

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

@Serializable
abstract class Project {
    abstract val name: String
}

@Serializable
@SerialName("OwnedProject")
data class OwnedProject(override val name: String, val owner: String) : Project()

val module = SerializersModule {
    polymorphic(Project::class) {
        subclass(OwnedProject::class)
    }
}

val format = Json { serializersModule = module }
-->  

```kotlin
fun main() {
    println(format.decodeFromString<Project>("""
        {"type":"unknown","name":"example"}
    """))
}
```

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

　以下のような例外が発生します。

```text 
Exception in thread "main" kotlinx.serialization.json.internal.JsonDecodingException: Polymorphic serializer was not found for class discriminator 'unknown'
```

<!--- TEST LINES_START -->

　フレキシブルな入力を読み込む際には、この場合のデフォルトの動作を提供したいと思うかもしれません。例えば、`BasicProject`のサブタイプを持つことで、あらゆる種類の未知の`Project`サブタイプを表現することができます。


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

```kotlin
@Serializable
abstract class Project {
    abstract val name: String
}

@Serializable
data class BasicProject(override val name: String, val type: String): Project()

@Serializable
@SerialName("OwnedProject")
data class OwnedProject(override val name: String, val owner: String) : Project()
```

　デフォルトハンドラを登録するには、[`polymorphic { ... }`][PolymorphicModuleBuilder] DSLの[`default`](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/-polymorphic-module-builder/default.html)関数を使用します。以下の例では、typeは使用せず、常に `BasicProject` クラスの [Plugin-generated serializer](https://qiita.com/guijiu/items/be7fa14c49cb7e3006dd#%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E7%94%9F%E6%88%90%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%B6) を返しています。 デフォルトハンドラは、入力の`type`文字列を[deserialization strategy][DeserializationStrategy]にマップするストラテジーを定義する[`polymorphic { ... }`][PolymorphicModuleBuilder] DSLの[`default`][PolymorphicModuleBuilder.default]関数を使用して登録します。以下の例では、型は使わず、常に `BasicProject` クラスの [Plugin-generated serializer](https://qiita.com/guijiu/items/be7fa14c49cb7e3006dd#%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E7%94%9F%E6%88%90%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%A9%E3%82%A4%E3%82%B6) を返すようにしています。 


```kotlin
val module = SerializersModule {
    polymorphic(Project::class) {
        subclass(OwnedProject::class)
        default { BasicProject.serializer() }
    }
}
```

　このモジュールを使うと、登録された `OwnedProject` のインスタンスと未登録のインスタンスの両方をデシリアライズすることができます。

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

fun main() {
    println(format.decodeFromString<List<Project>>("""
        [
            {"type":"unknown","name":"example"},
            {"type":"OwnedProject","name":"kotlinx.serialization","owner":"kotlin"} 
        ]
    """))
}
```

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

　BasicProject`は`type`プロパティで指定された型のキーも取得していることに注目してください。

```text
[BasicProject(name=example, type=unknown), OwnedProject(name=kotlinx.serialization, owner=kotlin)]
```

<!--- TEST -->

　プラグインで生成されたシリアライザをデフォルトのシリアライザとして使用し、「未知の」データの構造が事前にわかっていることを暗示しています。実際のAPIでは、このようなことはほとんどありません。そのためには、構造化されていないカスタムのシリアライザが必要です。
このようなシリアライザの例は、後述の[カスタムJSON属性のメンテナンス](https://qiita.com/guijiu/items/9bcbe7379026d88978da#%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0json%E5%B1%9E%E6%80%A7%E3%81%AE%E7%B6%AD%E6%8C%81)の項でご紹介します。

---

次の章では、[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)を取り上げます。

<!--- MODULE /kotlinx-serialization-core -->
<!--- INDEX kotlinx-serialization-core/kotlinx.serialization -->
[SerialName]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serial-name/index.html
[PolymorphicSerializer]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-polymorphic-serializer/index.html
[Serializable]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-serializable/index.html
[Polymorphic]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-polymorphic/index.html
[DeserializationStrategy]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization/-deserialization-strategy/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
[_polymorphic]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/polymorphic.html
[subclass]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/subclass.html
[plus]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/plus.html
[SerializersModuleBuilder.include]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module-builder/include.html
[PolymorphicModuleBuilder.default]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/-polymorphic-module-builder/default.html
[PolymorphicModuleBuilder]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx-serialization-core/kotlinx.serialization.modules/-polymorphic-module-builder/index.html
<!--- MODULE /kotlinx-serialization-json -->
<!--- INDEX kotlinx-serialization-json/kotlinx.serialization.json -->
[Json.encodeToString]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-json/kotlinx-serialization-json/kotlinx.serialization.json/-json/encode-to-string.html
[Json]: https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-json/kotlinx-serialization-json/kotlinx.serialization.json/-json/index.html
<!--- END -->