1*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST_NAME PolymorphismTest --> 2*57b5a4a6SAndroid Build Coastguard Worker 3*57b5a4a6SAndroid Build Coastguard Worker# Polymorphism 4*57b5a4a6SAndroid Build Coastguard Worker 5*57b5a4a6SAndroid Build Coastguard WorkerThis is the fourth chapter of the [Kotlin Serialization Guide](serialization-guide.md). 6*57b5a4a6SAndroid Build Coastguard WorkerIn this chapter we'll see how Kotlin Serialization deals with polymorphic class hierarchies. 7*57b5a4a6SAndroid Build Coastguard Worker 8*57b5a4a6SAndroid Build Coastguard Worker**Table of contents** 9*57b5a4a6SAndroid Build Coastguard Worker 10*57b5a4a6SAndroid Build Coastguard Worker<!--- TOC --> 11*57b5a4a6SAndroid Build Coastguard Worker 12*57b5a4a6SAndroid Build Coastguard Worker* [Closed polymorphism](#closed-polymorphism) 13*57b5a4a6SAndroid Build Coastguard Worker * [Static types](#static-types) 14*57b5a4a6SAndroid Build Coastguard Worker * [Designing serializable hierarchy](#designing-serializable-hierarchy) 15*57b5a4a6SAndroid Build Coastguard Worker * [Sealed classes](#sealed-classes) 16*57b5a4a6SAndroid Build Coastguard Worker * [Custom subclass serial name](#custom-subclass-serial-name) 17*57b5a4a6SAndroid Build Coastguard Worker * [Concrete properties in a base class](#concrete-properties-in-a-base-class) 18*57b5a4a6SAndroid Build Coastguard Worker * [Objects](#objects) 19*57b5a4a6SAndroid Build Coastguard Worker* [Open polymorphism](#open-polymorphism) 20*57b5a4a6SAndroid Build Coastguard Worker * [Registered subclasses](#registered-subclasses) 21*57b5a4a6SAndroid Build Coastguard Worker * [Serializing interfaces](#serializing-interfaces) 22*57b5a4a6SAndroid Build Coastguard Worker * [Property of an interface type](#property-of-an-interface-type) 23*57b5a4a6SAndroid Build Coastguard Worker * [Static parent type lookup for polymorphism](#static-parent-type-lookup-for-polymorphism) 24*57b5a4a6SAndroid Build Coastguard Worker * [Explicitly marking polymorphic class properties](#explicitly-marking-polymorphic-class-properties) 25*57b5a4a6SAndroid Build Coastguard Worker * [Registering multiple superclasses](#registering-multiple-superclasses) 26*57b5a4a6SAndroid Build Coastguard Worker * [Polymorphism and generic classes](#polymorphism-and-generic-classes) 27*57b5a4a6SAndroid Build Coastguard Worker * [Merging library serializers modules](#merging-library-serializers-modules) 28*57b5a4a6SAndroid Build Coastguard Worker * [Default polymorphic type handler for deserialization](#default-polymorphic-type-handler-for-deserialization) 29*57b5a4a6SAndroid Build Coastguard Worker * [Default polymorphic type handler for serialization](#default-polymorphic-type-handler-for-serialization) 30*57b5a4a6SAndroid Build Coastguard Worker 31*57b5a4a6SAndroid Build Coastguard Worker<!--- END --> 32*57b5a4a6SAndroid Build Coastguard Worker 33*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE .*-poly-.* 34*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.* 35*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.json.* 36*57b5a4a6SAndroid Build Coastguard Worker--> 37*57b5a4a6SAndroid Build Coastguard Worker 38*57b5a4a6SAndroid Build Coastguard Worker## Closed polymorphism 39*57b5a4a6SAndroid Build Coastguard Worker 40*57b5a4a6SAndroid Build Coastguard WorkerLet us start with basic introduction to polymorphism. 41*57b5a4a6SAndroid Build Coastguard Worker 42*57b5a4a6SAndroid Build Coastguard Worker### Static types 43*57b5a4a6SAndroid Build Coastguard Worker 44*57b5a4a6SAndroid Build Coastguard WorkerKotlin Serialization is fully static with respect to types by default. The structure of encoded objects is determined 45*57b5a4a6SAndroid Build Coastguard Workerby *compile-time* types of objects. Let's examine this aspect in more detail and learn how 46*57b5a4a6SAndroid Build Coastguard Workerto serialize polymorphic data structures, where the type of data is determined at runtime. 47*57b5a4a6SAndroid Build Coastguard Worker 48*57b5a4a6SAndroid Build Coastguard WorkerTo show the static nature of Kotlin Serialization let us make the following setup. An `open class Project` 49*57b5a4a6SAndroid Build Coastguard Workerhas just the `name` property, while its derived `class OwnedProject` adds an `owner` property. 50*57b5a4a6SAndroid Build Coastguard WorkerIn the below example, we serialize `data` variable with a static type of 51*57b5a4a6SAndroid Build Coastguard Worker`Project` that is initialized with an instance of `OwnedProject` at runtime. 52*57b5a4a6SAndroid Build Coastguard Worker 53*57b5a4a6SAndroid Build Coastguard Worker```kotlin 54*57b5a4a6SAndroid Build Coastguard Worker@Serializable 55*57b5a4a6SAndroid Build Coastguard Workeropen class Project(val name: String) 56*57b5a4a6SAndroid Build Coastguard Worker 57*57b5a4a6SAndroid Build Coastguard Workerclass OwnedProject(name: String, val owner: String) : Project(name) 58*57b5a4a6SAndroid Build Coastguard Worker 59*57b5a4a6SAndroid Build Coastguard Workerfun main() { 60*57b5a4a6SAndroid Build Coastguard Worker val data: Project = OwnedProject("kotlinx.coroutines", "kotlin") 61*57b5a4a6SAndroid Build Coastguard Worker println(Json.encodeToString(data)) 62*57b5a4a6SAndroid Build Coastguard Worker} 63*57b5a4a6SAndroid Build Coastguard Worker``` 64*57b5a4a6SAndroid Build Coastguard Worker 65*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-01.kt). 66*57b5a4a6SAndroid Build Coastguard Worker 67*57b5a4a6SAndroid Build Coastguard WorkerDespite the runtime type of `OwnedProject`, only the `Project` class properties are getting serialized. 68*57b5a4a6SAndroid Build Coastguard Worker 69*57b5a4a6SAndroid Build Coastguard Worker```text 70*57b5a4a6SAndroid Build Coastguard Worker{"name":"kotlinx.coroutines"} 71*57b5a4a6SAndroid Build Coastguard Worker``` 72*57b5a4a6SAndroid Build Coastguard Worker 73*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST --> 74*57b5a4a6SAndroid Build Coastguard Worker 75*57b5a4a6SAndroid Build Coastguard WorkerLet's change the compile-time type of `data` to `OwnedProject`. 76*57b5a4a6SAndroid Build Coastguard Worker 77*57b5a4a6SAndroid Build Coastguard Worker```kotlin 78*57b5a4a6SAndroid Build Coastguard Worker@Serializable 79*57b5a4a6SAndroid Build Coastguard Workeropen class Project(val name: String) 80*57b5a4a6SAndroid Build Coastguard Worker 81*57b5a4a6SAndroid Build Coastguard Workerclass OwnedProject(name: String, val owner: String) : Project(name) 82*57b5a4a6SAndroid Build Coastguard Worker 83*57b5a4a6SAndroid Build Coastguard Workerfun main() { 84*57b5a4a6SAndroid Build Coastguard Worker val data = OwnedProject("kotlinx.coroutines", "kotlin") 85*57b5a4a6SAndroid Build Coastguard Worker println(Json.encodeToString(data)) 86*57b5a4a6SAndroid Build Coastguard Worker} 87*57b5a4a6SAndroid Build Coastguard Worker``` 88*57b5a4a6SAndroid Build Coastguard Worker 89*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-02.kt). 90*57b5a4a6SAndroid Build Coastguard Worker 91*57b5a4a6SAndroid Build Coastguard WorkerWe get an error, because the `OwnedProject` class is not serializable. 92*57b5a4a6SAndroid Build Coastguard Worker 93*57b5a4a6SAndroid Build Coastguard Worker```text 94*57b5a4a6SAndroid Build Coastguard WorkerException in thread "main" kotlinx.serialization.SerializationException: Serializer for class 'OwnedProject' is not found. 95*57b5a4a6SAndroid Build Coastguard WorkerPlease ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied. 96*57b5a4a6SAndroid Build Coastguard Worker``` 97*57b5a4a6SAndroid Build Coastguard Worker 98*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST LINES_START --> 99*57b5a4a6SAndroid Build Coastguard Worker 100*57b5a4a6SAndroid Build Coastguard Worker### Designing serializable hierarchy 101*57b5a4a6SAndroid Build Coastguard Worker 102*57b5a4a6SAndroid Build Coastguard WorkerWe cannot simply mark `OwnedProject` from the previous example as `@Serializable`. It does not compile, 103*57b5a4a6SAndroid Build Coastguard Workerrunning into the [constructor properties requirement](basic-serialization.md#constructor-properties-requirement). 104*57b5a4a6SAndroid Build Coastguard WorkerTo make hierarchy of classes serializable, the properties in the parent class have to be marked `abstract`, 105*57b5a4a6SAndroid Build Coastguard Workermaking the `Project` class `abstract`, too. 106*57b5a4a6SAndroid Build Coastguard Worker 107*57b5a4a6SAndroid Build Coastguard Worker```kotlin 108*57b5a4a6SAndroid Build Coastguard Worker@Serializable 109*57b5a4a6SAndroid Build Coastguard Workerabstract class Project { 110*57b5a4a6SAndroid Build Coastguard Worker abstract val name: String 111*57b5a4a6SAndroid Build Coastguard Worker} 112*57b5a4a6SAndroid Build Coastguard Worker 113*57b5a4a6SAndroid Build Coastguard Workerclass OwnedProject(override val name: String, val owner: String) : Project() 114*57b5a4a6SAndroid Build Coastguard Worker 115*57b5a4a6SAndroid Build Coastguard Workerfun main() { 116*57b5a4a6SAndroid Build Coastguard Worker val data: Project = OwnedProject("kotlinx.coroutines", "kotlin") 117*57b5a4a6SAndroid Build Coastguard Worker println(Json.encodeToString(data)) 118*57b5a4a6SAndroid Build Coastguard Worker} 119*57b5a4a6SAndroid Build Coastguard Worker``` 120*57b5a4a6SAndroid Build Coastguard Worker 121*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-03.kt). 122*57b5a4a6SAndroid Build Coastguard Worker 123*57b5a4a6SAndroid Build Coastguard WorkerThis is close to the best design for a serializable hierarchy of classes, but running it produces the following error: 124*57b5a4a6SAndroid Build Coastguard Worker 125*57b5a4a6SAndroid Build Coastguard Worker```text 126*57b5a4a6SAndroid Build Coastguard WorkerException in thread "main" kotlinx.serialization.SerializationException: Serializer for subclass 'OwnedProject' is not found in the polymorphic scope of 'Project'. 127*57b5a4a6SAndroid Build Coastguard WorkerCheck if class with serial name 'OwnedProject' exists and serializer is registered in a corresponding SerializersModule. 128*57b5a4a6SAndroid Build Coastguard WorkerTo be registered automatically, class 'OwnedProject' has to be '@Serializable', and the base class 'Project' has to be sealed and '@Serializable'. 129*57b5a4a6SAndroid Build Coastguard Worker``` 130*57b5a4a6SAndroid Build Coastguard Worker 131*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST LINES_START --> 132*57b5a4a6SAndroid Build Coastguard Worker 133*57b5a4a6SAndroid Build Coastguard Worker### Sealed classes 134*57b5a4a6SAndroid Build Coastguard Worker 135*57b5a4a6SAndroid Build Coastguard WorkerThe most straightforward way to use serialization with a polymorphic hierarchy is to mark the base class `sealed`. 136*57b5a4a6SAndroid Build Coastguard Worker_All_ subclasses of a sealed class must be explicitly marked as `@Serializable`. 137*57b5a4a6SAndroid Build Coastguard Worker 138*57b5a4a6SAndroid Build Coastguard Worker```kotlin 139*57b5a4a6SAndroid Build Coastguard Worker@Serializable 140*57b5a4a6SAndroid Build Coastguard Workersealed class Project { 141*57b5a4a6SAndroid Build Coastguard Worker abstract val name: String 142*57b5a4a6SAndroid Build Coastguard Worker} 143*57b5a4a6SAndroid Build Coastguard Worker 144*57b5a4a6SAndroid Build Coastguard Worker@Serializable 145*57b5a4a6SAndroid Build Coastguard Workerclass OwnedProject(override val name: String, val owner: String) : Project() 146*57b5a4a6SAndroid Build Coastguard Worker 147*57b5a4a6SAndroid Build Coastguard Workerfun main() { 148*57b5a4a6SAndroid Build Coastguard Worker val data: Project = OwnedProject("kotlinx.coroutines", "kotlin") 149*57b5a4a6SAndroid Build Coastguard Worker println(Json.encodeToString(data)) // Serializing data of compile-time type Project 150*57b5a4a6SAndroid Build Coastguard Worker} 151*57b5a4a6SAndroid Build Coastguard Worker``` 152*57b5a4a6SAndroid Build Coastguard Worker 153*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-04.kt). 154*57b5a4a6SAndroid Build Coastguard Worker 155*57b5a4a6SAndroid Build Coastguard WorkerNow we can see a default way to represent polymorphism in JSON. 156*57b5a4a6SAndroid Build Coastguard WorkerA `type` key is added to the resulting JSON object as a _discriminator_. 157*57b5a4a6SAndroid Build Coastguard Worker 158*57b5a4a6SAndroid Build Coastguard Worker```text 159*57b5a4a6SAndroid Build Coastguard Worker{"type":"example.examplePoly04.OwnedProject","name":"kotlinx.coroutines","owner":"kotlin"} 160*57b5a4a6SAndroid Build Coastguard Worker``` 161*57b5a4a6SAndroid Build Coastguard Worker 162*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST --> 163*57b5a4a6SAndroid Build Coastguard Worker 164*57b5a4a6SAndroid Build Coastguard WorkerPay attention to the small, but very important detail in the above example that is related to [Static types](#static-types): 165*57b5a4a6SAndroid Build Coastguard Workerthe `val data` property has a compile-time type of `Project`, even though its run-time type is `OwnedProject`. 166*57b5a4a6SAndroid Build Coastguard WorkerWhen serializing polymorphic class hierarchies you must ensure that the compile-time type of the serialized object 167*57b5a4a6SAndroid Build Coastguard Workeris a polymorphic one, not a concrete one. 168*57b5a4a6SAndroid Build Coastguard Worker 169*57b5a4a6SAndroid Build Coastguard WorkerLet us see what happens if the example is slightly changed, so that the compile-time of the object that is being 170*57b5a4a6SAndroid Build Coastguard Workerserialized is `OwnedProject` (the same as its run-time type). 171*57b5a4a6SAndroid Build Coastguard Worker 172*57b5a4a6SAndroid Build Coastguard Worker```kotlin 173*57b5a4a6SAndroid Build Coastguard Worker@Serializable 174*57b5a4a6SAndroid Build Coastguard Workersealed class Project { 175*57b5a4a6SAndroid Build Coastguard Worker abstract val name: String 176*57b5a4a6SAndroid Build Coastguard Worker} 177*57b5a4a6SAndroid Build Coastguard Worker 178*57b5a4a6SAndroid Build Coastguard Worker@Serializable 179*57b5a4a6SAndroid Build Coastguard Workerclass OwnedProject(override val name: String, val owner: String) : Project() 180*57b5a4a6SAndroid Build Coastguard Worker 181*57b5a4a6SAndroid Build Coastguard Workerfun main() { 182*57b5a4a6SAndroid Build Coastguard Worker val data = OwnedProject("kotlinx.coroutines", "kotlin") // data: OwnedProject here 183*57b5a4a6SAndroid Build Coastguard Worker println(Json.encodeToString(data)) // Serializing data of compile-time type OwnedProject 184*57b5a4a6SAndroid Build Coastguard Worker} 185*57b5a4a6SAndroid Build Coastguard Worker``` 186*57b5a4a6SAndroid Build Coastguard Worker 187*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-05.kt). 188*57b5a4a6SAndroid Build Coastguard Worker 189*57b5a4a6SAndroid Build Coastguard WorkerThe type of `OwnedProject` is concrete and is not polymorphic, thus the `type` 190*57b5a4a6SAndroid Build Coastguard Workerdiscriminator property is not emitted into the resulting JSON. 191*57b5a4a6SAndroid Build Coastguard Worker 192*57b5a4a6SAndroid Build Coastguard Worker```text 193*57b5a4a6SAndroid Build Coastguard Worker{"name":"kotlinx.coroutines","owner":"kotlin"} 194*57b5a4a6SAndroid Build Coastguard Worker``` 195*57b5a4a6SAndroid Build Coastguard Worker 196*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST --> 197*57b5a4a6SAndroid Build Coastguard Worker 198*57b5a4a6SAndroid Build Coastguard WorkerIn general, Kotlin Serialization is designed to work correctly only when the compile-time type used during serialization 199*57b5a4a6SAndroid Build Coastguard Workeris the same one as the compile-time type used during deserialization. You can always specify the type explicitly 200*57b5a4a6SAndroid Build Coastguard Workerwhen calling serialization functions. The previous example can be corrected to use `Project` type for serialization 201*57b5a4a6SAndroid Build Coastguard Workerby calling `Json.encodeToString<Project>(data)`. 202*57b5a4a6SAndroid Build Coastguard Worker 203*57b5a4a6SAndroid Build Coastguard Worker### Custom subclass serial name 204*57b5a4a6SAndroid Build Coastguard Worker 205*57b5a4a6SAndroid Build Coastguard WorkerA value of the `type` key is a fully qualified class name by default. We can put [SerialName] annotation onto 206*57b5a4a6SAndroid Build Coastguard Workerthe corresponding class to change it. 207*57b5a4a6SAndroid Build Coastguard Worker 208*57b5a4a6SAndroid Build Coastguard Worker```kotlin 209*57b5a4a6SAndroid Build Coastguard Worker@Serializable 210*57b5a4a6SAndroid Build Coastguard Workersealed class Project { 211*57b5a4a6SAndroid Build Coastguard Worker abstract val name: String 212*57b5a4a6SAndroid Build Coastguard Worker} 213*57b5a4a6SAndroid Build Coastguard Worker 214*57b5a4a6SAndroid Build Coastguard Worker@Serializable 215*57b5a4a6SAndroid Build Coastguard Worker@SerialName("owned") 216*57b5a4a6SAndroid Build Coastguard Workerclass OwnedProject(override val name: String, val owner: String) : Project() 217*57b5a4a6SAndroid Build Coastguard Worker 218*57b5a4a6SAndroid Build Coastguard Workerfun main() { 219*57b5a4a6SAndroid Build Coastguard Worker val data: Project = OwnedProject("kotlinx.coroutines", "kotlin") 220*57b5a4a6SAndroid Build Coastguard Worker println(Json.encodeToString(data)) 221*57b5a4a6SAndroid Build Coastguard Worker} 222*57b5a4a6SAndroid Build Coastguard Worker``` 223*57b5a4a6SAndroid Build Coastguard Worker 224*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-06.kt). 225*57b5a4a6SAndroid Build Coastguard Worker 226*57b5a4a6SAndroid Build Coastguard WorkerThis way we can have a stable _serial name_ that is not affected by the class's name in the source code. 227*57b5a4a6SAndroid Build Coastguard Worker 228*57b5a4a6SAndroid Build Coastguard Worker```text 229*57b5a4a6SAndroid Build Coastguard Worker{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"} 230*57b5a4a6SAndroid Build Coastguard Worker``` 231*57b5a4a6SAndroid Build Coastguard Worker 232*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST --> 233*57b5a4a6SAndroid Build Coastguard Worker 234*57b5a4a6SAndroid Build Coastguard Worker> In addition to that, JSON can be configured to use a different key name for the class discriminator. 235*57b5a4a6SAndroid Build Coastguard Worker> You can find an example in the [Class discriminator for polymorphism](json.md#class-discriminator-for-polymorphism) section. 236*57b5a4a6SAndroid Build Coastguard Worker 237*57b5a4a6SAndroid Build Coastguard Worker### Concrete properties in a base class 238*57b5a4a6SAndroid Build Coastguard Worker 239*57b5a4a6SAndroid Build Coastguard WorkerA base class in a sealed hierarchy can have properties with backing fields. 240*57b5a4a6SAndroid Build Coastguard Worker 241*57b5a4a6SAndroid Build Coastguard Worker```kotlin 242*57b5a4a6SAndroid Build Coastguard Worker@Serializable 243*57b5a4a6SAndroid Build Coastguard Workersealed class Project { 244*57b5a4a6SAndroid Build Coastguard Worker abstract val name: String 245*57b5a4a6SAndroid Build Coastguard Worker var status = "open" 246*57b5a4a6SAndroid Build Coastguard Worker} 247*57b5a4a6SAndroid Build Coastguard Worker 248*57b5a4a6SAndroid Build Coastguard Worker@Serializable 249*57b5a4a6SAndroid Build Coastguard Worker@SerialName("owned") 250*57b5a4a6SAndroid Build Coastguard Workerclass OwnedProject(override val name: String, val owner: String) : Project() 251*57b5a4a6SAndroid Build Coastguard Worker 252*57b5a4a6SAndroid Build Coastguard Workerfun main() { 253*57b5a4a6SAndroid Build Coastguard Worker val json = Json { encodeDefaults = true } // "status" will be skipped otherwise 254*57b5a4a6SAndroid Build Coastguard Worker val data: Project = OwnedProject("kotlinx.coroutines", "kotlin") 255*57b5a4a6SAndroid Build Coastguard Worker println(json.encodeToString(data)) 256*57b5a4a6SAndroid Build Coastguard Worker} 257*57b5a4a6SAndroid Build Coastguard Worker``` 258*57b5a4a6SAndroid Build Coastguard Worker 259*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-07.kt). 260*57b5a4a6SAndroid Build Coastguard Worker 261*57b5a4a6SAndroid Build Coastguard WorkerThe properties of the superclass are serialized before the properties of the subclass. 262*57b5a4a6SAndroid Build Coastguard Worker 263*57b5a4a6SAndroid Build Coastguard Worker```text 264*57b5a4a6SAndroid Build Coastguard Worker{"type":"owned","status":"open","name":"kotlinx.coroutines","owner":"kotlin"} 265*57b5a4a6SAndroid Build Coastguard Worker``` 266*57b5a4a6SAndroid Build Coastguard Worker 267*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST --> 268*57b5a4a6SAndroid Build Coastguard Worker 269*57b5a4a6SAndroid Build Coastguard Worker### Objects 270*57b5a4a6SAndroid Build Coastguard Worker 271*57b5a4a6SAndroid Build Coastguard WorkerSealed hierarchies can have objects as their subclasses and they also need to be marked as `@Serializable`. 272*57b5a4a6SAndroid Build Coastguard WorkerLet's take a different example with a hierarchy of `Response` classes. 273*57b5a4a6SAndroid Build Coastguard Worker 274*57b5a4a6SAndroid Build Coastguard Worker```kotlin 275*57b5a4a6SAndroid Build Coastguard Worker@Serializable 276*57b5a4a6SAndroid Build Coastguard Workersealed class Response 277*57b5a4a6SAndroid Build Coastguard Worker 278*57b5a4a6SAndroid Build Coastguard Worker@Serializable 279*57b5a4a6SAndroid Build Coastguard Workerobject EmptyResponse : Response() 280*57b5a4a6SAndroid Build Coastguard Worker 281*57b5a4a6SAndroid Build Coastguard Worker@Serializable 282*57b5a4a6SAndroid Build Coastguard Workerclass TextResponse(val text: String) : Response() 283*57b5a4a6SAndroid Build Coastguard Worker``` 284*57b5a4a6SAndroid Build Coastguard Worker 285*57b5a4a6SAndroid Build Coastguard WorkerLet us serialize a list of different responses. 286*57b5a4a6SAndroid Build Coastguard Worker 287*57b5a4a6SAndroid Build Coastguard Worker```kotlin 288*57b5a4a6SAndroid Build Coastguard Workerfun main() { 289*57b5a4a6SAndroid Build Coastguard Worker val list = listOf(EmptyResponse, TextResponse("OK")) 290*57b5a4a6SAndroid Build Coastguard Worker println(Json.encodeToString(list)) 291*57b5a4a6SAndroid Build Coastguard Worker} 292*57b5a4a6SAndroid Build Coastguard Worker``` 293*57b5a4a6SAndroid Build Coastguard Worker 294*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-08.kt). 295*57b5a4a6SAndroid Build Coastguard Worker 296*57b5a4a6SAndroid Build Coastguard WorkerAn object serializes as an empty class, also using its fully-qualified class name as type by default: 297*57b5a4a6SAndroid Build Coastguard Worker 298*57b5a4a6SAndroid Build Coastguard Worker```text 299*57b5a4a6SAndroid Build Coastguard Worker[{"type":"example.examplePoly08.EmptyResponse"},{"type":"example.examplePoly08.TextResponse","text":"OK"}] 300*57b5a4a6SAndroid Build Coastguard Worker``` 301*57b5a4a6SAndroid Build Coastguard Worker 302*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST --> 303*57b5a4a6SAndroid Build Coastguard Worker 304*57b5a4a6SAndroid Build Coastguard Worker> Even if object has properties, they are not serialized. 305*57b5a4a6SAndroid Build Coastguard Worker 306*57b5a4a6SAndroid Build Coastguard Worker## Open polymorphism 307*57b5a4a6SAndroid Build Coastguard Worker 308*57b5a4a6SAndroid Build Coastguard WorkerSerialization can work with arbitrary `open` classes or `abstract` classes. 309*57b5a4a6SAndroid Build Coastguard WorkerHowever, since this kind of polymorphism is open, there is a possibility that subclasses are defined anywhere in the 310*57b5a4a6SAndroid Build Coastguard Workersource code, even in other modules, the list of subclasses that are serialized cannot be determined at compile-time and 311*57b5a4a6SAndroid Build Coastguard Workermust be explicitly registered at runtime. 312*57b5a4a6SAndroid Build Coastguard Worker 313*57b5a4a6SAndroid Build Coastguard Worker### Registered subclasses 314*57b5a4a6SAndroid Build Coastguard Worker 315*57b5a4a6SAndroid Build Coastguard WorkerLet us start with the code from the [Designing serializable hierarchy](#designing-serializable-hierarchy) section. 316*57b5a4a6SAndroid Build Coastguard WorkerTo make it work with serialization without making it `sealed`, we have to define a [SerializersModule] using the 317*57b5a4a6SAndroid Build Coastguard Worker[SerializersModule {}][SerializersModule()] builder function. In the module the base class is specified 318*57b5a4a6SAndroid Build Coastguard Workerin the [polymorphic][_polymorphic] builder and each subclass is registered with the [subclass] function. Now, 319*57b5a4a6SAndroid Build Coastguard Workera custom JSON configuration can be instantiated with this module and used for serialization. 320*57b5a4a6SAndroid Build Coastguard Worker 321*57b5a4a6SAndroid Build Coastguard Worker> Details on custom JSON configurations can be found in 322*57b5a4a6SAndroid Build Coastguard Worker> the [JSON configuration](json.md#json-configuration) section. 323*57b5a4a6SAndroid Build Coastguard Worker 324*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE 325*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.* 326*57b5a4a6SAndroid Build Coastguard Worker--> 327*57b5a4a6SAndroid Build Coastguard Worker 328*57b5a4a6SAndroid Build Coastguard Worker```kotlin 329*57b5a4a6SAndroid Build Coastguard Workerval module = SerializersModule { 330*57b5a4a6SAndroid Build Coastguard Worker polymorphic(Project::class) { 331*57b5a4a6SAndroid Build Coastguard Worker subclass(OwnedProject::class) 332*57b5a4a6SAndroid Build Coastguard Worker } 333*57b5a4a6SAndroid Build Coastguard Worker} 334*57b5a4a6SAndroid Build Coastguard Worker 335*57b5a4a6SAndroid Build Coastguard Workerval format = Json { serializersModule = module } 336*57b5a4a6SAndroid Build Coastguard Worker 337*57b5a4a6SAndroid Build Coastguard Worker@Serializable 338*57b5a4a6SAndroid Build Coastguard Workerabstract class Project { 339*57b5a4a6SAndroid Build Coastguard Worker abstract val name: String 340*57b5a4a6SAndroid Build Coastguard Worker} 341*57b5a4a6SAndroid Build Coastguard Worker 342*57b5a4a6SAndroid Build Coastguard Worker@Serializable 343*57b5a4a6SAndroid Build Coastguard Worker@SerialName("owned") 344*57b5a4a6SAndroid Build Coastguard Workerclass OwnedProject(override val name: String, val owner: String) : Project() 345*57b5a4a6SAndroid Build Coastguard Worker 346*57b5a4a6SAndroid Build Coastguard Workerfun main() { 347*57b5a4a6SAndroid Build Coastguard Worker val data: Project = OwnedProject("kotlinx.coroutines", "kotlin") 348*57b5a4a6SAndroid Build Coastguard Worker println(format.encodeToString(data)) 349*57b5a4a6SAndroid Build Coastguard Worker} 350*57b5a4a6SAndroid Build Coastguard Worker``` 351*57b5a4a6SAndroid Build Coastguard Worker 352*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-09.kt). 353*57b5a4a6SAndroid Build Coastguard Worker 354*57b5a4a6SAndroid Build Coastguard WorkerThis additional configuration makes our code work just as it worked with a sealed class in 355*57b5a4a6SAndroid Build Coastguard Workerthe [Sealed classes](#sealed-classes) section, but here subclasses can be spread arbitrarily throughout the code. 356*57b5a4a6SAndroid Build Coastguard Worker 357*57b5a4a6SAndroid Build Coastguard Worker```text 358*57b5a4a6SAndroid Build Coastguard Worker{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"} 359*57b5a4a6SAndroid Build Coastguard Worker``` 360*57b5a4a6SAndroid Build Coastguard Worker 361*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST --> 362*57b5a4a6SAndroid Build Coastguard Worker>Please note that this example works only on JVM because of `serializer` function restrictions. 363*57b5a4a6SAndroid Build Coastguard Worker>For JS and Native, explicit serializer should be used: `format.encodeToString(PolymorphicSerializer(Project::class), data)` 364*57b5a4a6SAndroid Build Coastguard Worker>You can keep track of this issue [here](https://github.com/Kotlin/kotlinx.serialization/issues/1077). 365*57b5a4a6SAndroid Build Coastguard Worker 366*57b5a4a6SAndroid Build Coastguard Worker### Serializing interfaces 367*57b5a4a6SAndroid Build Coastguard Worker 368*57b5a4a6SAndroid Build Coastguard WorkerWe can update the previous example and turn `Project` superclass into an interface. However, we cannot 369*57b5a4a6SAndroid Build Coastguard Workermark an interface itself as `@Serializable`. No problem. Interfaces cannot have instances by themselves. 370*57b5a4a6SAndroid Build Coastguard WorkerInterfaces can only be represented by instances of their derived classes. Interfaces are used in the Kotlin language to enable polymorphism, 371*57b5a4a6SAndroid Build Coastguard Workerso all interfaces are considered to be implicitly serializable with the [PolymorphicSerializer] 372*57b5a4a6SAndroid Build Coastguard Workerstrategy. We just need to mark their implementing classes as `@Serializable` and register them. 373*57b5a4a6SAndroid Build Coastguard Worker 374*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE 375*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.* 376*57b5a4a6SAndroid Build Coastguard Worker 377*57b5a4a6SAndroid Build Coastguard Workerval module = SerializersModule { 378*57b5a4a6SAndroid Build Coastguard Worker polymorphic(Project::class) { 379*57b5a4a6SAndroid Build Coastguard Worker subclass(OwnedProject::class) 380*57b5a4a6SAndroid Build Coastguard Worker } 381*57b5a4a6SAndroid Build Coastguard Worker} 382*57b5a4a6SAndroid Build Coastguard Worker 383*57b5a4a6SAndroid Build Coastguard Workerval format = Json { serializersModule = module } 384*57b5a4a6SAndroid Build Coastguard Worker--> 385*57b5a4a6SAndroid Build Coastguard Worker 386*57b5a4a6SAndroid Build Coastguard Worker```kotlin 387*57b5a4a6SAndroid Build Coastguard Workerinterface Project { 388*57b5a4a6SAndroid Build Coastguard Worker val name: String 389*57b5a4a6SAndroid Build Coastguard Worker} 390*57b5a4a6SAndroid Build Coastguard Worker 391*57b5a4a6SAndroid Build Coastguard Worker@Serializable 392*57b5a4a6SAndroid Build Coastguard Worker@SerialName("owned") 393*57b5a4a6SAndroid Build Coastguard Workerclass OwnedProject(override val name: String, val owner: String) : Project 394*57b5a4a6SAndroid Build Coastguard Worker``` 395*57b5a4a6SAndroid Build Coastguard Worker 396*57b5a4a6SAndroid Build Coastguard WorkerNow if we declare `data` with the type of `Project` we can simply call `format.encodeToString` as before. 397*57b5a4a6SAndroid Build Coastguard Worker 398*57b5a4a6SAndroid Build Coastguard Worker```kotlin 399*57b5a4a6SAndroid Build Coastguard Workerfun main() { 400*57b5a4a6SAndroid Build Coastguard Worker val data: Project = OwnedProject("kotlinx.coroutines", "kotlin") 401*57b5a4a6SAndroid Build Coastguard Worker println(format.encodeToString(data)) 402*57b5a4a6SAndroid Build Coastguard Worker} 403*57b5a4a6SAndroid Build Coastguard Worker``` 404*57b5a4a6SAndroid Build Coastguard Worker 405*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-10.kt). 406*57b5a4a6SAndroid Build Coastguard Worker 407*57b5a4a6SAndroid Build Coastguard Worker```text 408*57b5a4a6SAndroid Build Coastguard Worker{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"} 409*57b5a4a6SAndroid Build Coastguard Worker``` 410*57b5a4a6SAndroid Build Coastguard Worker 411*57b5a4a6SAndroid Build Coastguard Worker> Note: On Kotlin/Native, you should use `format.encodeToString(PolymorphicSerializer(Project::class), data))` instead due to limited reflection capabilities. 412*57b5a4a6SAndroid Build Coastguard Worker 413*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST LINES_START --> 414*57b5a4a6SAndroid Build Coastguard Worker 415*57b5a4a6SAndroid Build Coastguard Worker### Property of an interface type 416*57b5a4a6SAndroid Build Coastguard Worker 417*57b5a4a6SAndroid Build Coastguard WorkerContinuing the previous example, let us see what happens if we use `Project` interface as a property in some 418*57b5a4a6SAndroid Build Coastguard Workerother serializable class. Interfaces are implicitly polymorphic, so we can just declare a property of an interface type. 419*57b5a4a6SAndroid Build Coastguard Worker 420*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE 421*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.* 422*57b5a4a6SAndroid Build Coastguard Worker 423*57b5a4a6SAndroid Build Coastguard Workerval module = SerializersModule { 424*57b5a4a6SAndroid Build Coastguard Worker polymorphic(Project::class) { 425*57b5a4a6SAndroid Build Coastguard Worker subclass(OwnedProject::class) 426*57b5a4a6SAndroid Build Coastguard Worker } 427*57b5a4a6SAndroid Build Coastguard Worker} 428*57b5a4a6SAndroid Build Coastguard Worker 429*57b5a4a6SAndroid Build Coastguard Workerval format = Json { serializersModule = module } 430*57b5a4a6SAndroid Build Coastguard Worker 431*57b5a4a6SAndroid Build Coastguard Workerinterface Project { 432*57b5a4a6SAndroid Build Coastguard Worker val name: String 433*57b5a4a6SAndroid Build Coastguard Worker} 434*57b5a4a6SAndroid Build Coastguard Worker 435*57b5a4a6SAndroid Build Coastguard Worker@Serializable 436*57b5a4a6SAndroid Build Coastguard Worker@SerialName("owned") 437*57b5a4a6SAndroid Build Coastguard Workerclass OwnedProject(override val name: String, val owner: String) : Project 438*57b5a4a6SAndroid Build Coastguard Worker--> 439*57b5a4a6SAndroid Build Coastguard Worker 440*57b5a4a6SAndroid Build Coastguard Worker```kotlin 441*57b5a4a6SAndroid Build Coastguard Worker@Serializable 442*57b5a4a6SAndroid Build Coastguard Workerclass Data(val project: Project) // Project is an interface 443*57b5a4a6SAndroid Build Coastguard Worker 444*57b5a4a6SAndroid Build Coastguard Workerfun main() { 445*57b5a4a6SAndroid Build Coastguard Worker val data = Data(OwnedProject("kotlinx.coroutines", "kotlin")) 446*57b5a4a6SAndroid Build Coastguard Worker println(format.encodeToString(data)) 447*57b5a4a6SAndroid Build Coastguard Worker} 448*57b5a4a6SAndroid Build Coastguard Worker``` 449*57b5a4a6SAndroid Build Coastguard Worker 450*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-11.kt). 451*57b5a4a6SAndroid Build Coastguard Worker 452*57b5a4a6SAndroid Build Coastguard WorkerAs long as we've registered the actual subtype of the interface that is being serialized in 453*57b5a4a6SAndroid Build Coastguard Workerthe [SerializersModule] of our `format`, we get it working at runtime. 454*57b5a4a6SAndroid Build Coastguard Worker 455*57b5a4a6SAndroid Build Coastguard Worker```text 456*57b5a4a6SAndroid Build Coastguard Worker{"project":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}} 457*57b5a4a6SAndroid Build Coastguard Worker``` 458*57b5a4a6SAndroid Build Coastguard Worker 459*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST --> 460*57b5a4a6SAndroid Build Coastguard Worker 461*57b5a4a6SAndroid Build Coastguard Worker### Static parent type lookup for polymorphism 462*57b5a4a6SAndroid Build Coastguard Worker 463*57b5a4a6SAndroid Build Coastguard WorkerDuring serialization of a polymorphic class the root type of the polymorphic hierarchy (`Project` in our example) 464*57b5a4a6SAndroid Build Coastguard Workeris determined statically. Let us take the example with the serializable `abstract class Project`, 465*57b5a4a6SAndroid Build Coastguard Workerbut change the `main` function to declare `data` as having a type of `Any`: 466*57b5a4a6SAndroid Build Coastguard Worker 467*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE 468*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.* 469*57b5a4a6SAndroid Build Coastguard Worker 470*57b5a4a6SAndroid Build Coastguard Workerval module = SerializersModule { 471*57b5a4a6SAndroid Build Coastguard Worker polymorphic(Project::class) { 472*57b5a4a6SAndroid Build Coastguard Worker subclass(OwnedProject::class) 473*57b5a4a6SAndroid Build Coastguard Worker } 474*57b5a4a6SAndroid Build Coastguard Worker} 475*57b5a4a6SAndroid Build Coastguard Worker 476*57b5a4a6SAndroid Build Coastguard Workerval format = Json { serializersModule = module } 477*57b5a4a6SAndroid Build Coastguard Worker 478*57b5a4a6SAndroid Build Coastguard Worker@Serializable 479*57b5a4a6SAndroid Build Coastguard Workerabstract class Project { 480*57b5a4a6SAndroid Build Coastguard Worker abstract val name: String 481*57b5a4a6SAndroid Build Coastguard Worker} 482*57b5a4a6SAndroid Build Coastguard Worker 483*57b5a4a6SAndroid Build Coastguard Worker@Serializable 484*57b5a4a6SAndroid Build Coastguard Worker@SerialName("owned") 485*57b5a4a6SAndroid Build Coastguard Workerclass OwnedProject(override val name: String, val owner: String) : Project() 486*57b5a4a6SAndroid Build Coastguard Worker--> 487*57b5a4a6SAndroid Build Coastguard Worker 488*57b5a4a6SAndroid Build Coastguard Worker```kotlin 489*57b5a4a6SAndroid Build Coastguard Workerfun main() { 490*57b5a4a6SAndroid Build Coastguard Worker val data: Any = OwnedProject("kotlinx.coroutines", "kotlin") 491*57b5a4a6SAndroid Build Coastguard Worker println(format.encodeToString(data)) 492*57b5a4a6SAndroid Build Coastguard Worker} 493*57b5a4a6SAndroid Build Coastguard Worker``` 494*57b5a4a6SAndroid Build Coastguard Worker 495*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-12.kt). 496*57b5a4a6SAndroid Build Coastguard Worker 497*57b5a4a6SAndroid Build Coastguard WorkerWe get the exception. 498*57b5a4a6SAndroid Build Coastguard Worker 499*57b5a4a6SAndroid Build Coastguard Worker```text 500*57b5a4a6SAndroid Build Coastguard WorkerException in thread "main" kotlinx.serialization.SerializationException: Serializer for class 'Any' is not found. 501*57b5a4a6SAndroid Build Coastguard WorkerPlease ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied. 502*57b5a4a6SAndroid Build Coastguard Worker``` 503*57b5a4a6SAndroid Build Coastguard Worker 504*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST LINES_START --> 505*57b5a4a6SAndroid Build Coastguard Worker 506*57b5a4a6SAndroid Build Coastguard WorkerWe have to register classes for polymorphic serialization with respect for the corresponding static type we 507*57b5a4a6SAndroid Build Coastguard Workeruse in the source code. First of all, we change our module to register a subclass of `Any`: 508*57b5a4a6SAndroid Build Coastguard Worker 509*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE 510*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.* 511*57b5a4a6SAndroid Build Coastguard Worker--> 512*57b5a4a6SAndroid Build Coastguard Worker 513*57b5a4a6SAndroid Build Coastguard Worker```kotlin 514*57b5a4a6SAndroid Build Coastguard Workerval module = SerializersModule { 515*57b5a4a6SAndroid Build Coastguard Worker polymorphic(Any::class) { 516*57b5a4a6SAndroid Build Coastguard Worker subclass(OwnedProject::class) 517*57b5a4a6SAndroid Build Coastguard Worker } 518*57b5a4a6SAndroid Build Coastguard Worker} 519*57b5a4a6SAndroid Build Coastguard Worker``` 520*57b5a4a6SAndroid Build Coastguard Worker 521*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE 522*57b5a4a6SAndroid Build Coastguard Workerval format = Json { serializersModule = module } 523*57b5a4a6SAndroid Build Coastguard Worker 524*57b5a4a6SAndroid Build Coastguard Worker@Serializable 525*57b5a4a6SAndroid Build Coastguard Workerabstract class Project { 526*57b5a4a6SAndroid Build Coastguard Worker abstract val name: String 527*57b5a4a6SAndroid Build Coastguard Worker} 528*57b5a4a6SAndroid Build Coastguard Worker 529*57b5a4a6SAndroid Build Coastguard Worker@Serializable 530*57b5a4a6SAndroid Build Coastguard Worker@SerialName("owned") 531*57b5a4a6SAndroid Build Coastguard Workerclass OwnedProject(override val name: String, val owner: String) : Project() 532*57b5a4a6SAndroid Build Coastguard Worker--> 533*57b5a4a6SAndroid Build Coastguard Worker 534*57b5a4a6SAndroid Build Coastguard WorkerThen we can try to serialize the variable of type `Any`: 535*57b5a4a6SAndroid Build Coastguard Worker 536*57b5a4a6SAndroid Build Coastguard Worker```kotlin 537*57b5a4a6SAndroid Build Coastguard Workerfun main() { 538*57b5a4a6SAndroid Build Coastguard Worker val data: Any = OwnedProject("kotlinx.coroutines", "kotlin") 539*57b5a4a6SAndroid Build Coastguard Worker println(format.encodeToString(data)) 540*57b5a4a6SAndroid Build Coastguard Worker} 541*57b5a4a6SAndroid Build Coastguard Worker``` 542*57b5a4a6SAndroid Build Coastguard Worker 543*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-13.kt). 544*57b5a4a6SAndroid Build Coastguard Worker 545*57b5a4a6SAndroid Build Coastguard WorkerHowever, `Any` is a class and it is not serializable: 546*57b5a4a6SAndroid Build Coastguard Worker 547*57b5a4a6SAndroid Build Coastguard Worker```text 548*57b5a4a6SAndroid Build Coastguard WorkerException in thread "main" kotlinx.serialization.SerializationException: Serializer for class 'Any' is not found. 549*57b5a4a6SAndroid Build Coastguard WorkerPlease ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied. 550*57b5a4a6SAndroid Build Coastguard Worker``` 551*57b5a4a6SAndroid Build Coastguard Worker 552*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST LINES_START --> 553*57b5a4a6SAndroid Build Coastguard Worker 554*57b5a4a6SAndroid Build Coastguard WorkerWe must to explicitly pass an instance of [PolymorphicSerializer] for the base class `Any` as the 555*57b5a4a6SAndroid Build Coastguard Workerfirst parameter to the [encodeToString][Json.encodeToString] function. 556*57b5a4a6SAndroid Build Coastguard Worker 557*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE 558*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.* 559*57b5a4a6SAndroid Build Coastguard Worker 560*57b5a4a6SAndroid Build Coastguard Workerval module = SerializersModule { 561*57b5a4a6SAndroid Build Coastguard Worker polymorphic(Any::class) { 562*57b5a4a6SAndroid Build Coastguard Worker subclass(OwnedProject::class) 563*57b5a4a6SAndroid Build Coastguard Worker } 564*57b5a4a6SAndroid Build Coastguard Worker} 565*57b5a4a6SAndroid Build Coastguard Worker 566*57b5a4a6SAndroid Build Coastguard Workerval format = Json { serializersModule = module } 567*57b5a4a6SAndroid Build Coastguard Worker 568*57b5a4a6SAndroid Build Coastguard Worker@Serializable 569*57b5a4a6SAndroid Build Coastguard Workerabstract class Project { 570*57b5a4a6SAndroid Build Coastguard Worker abstract val name: String 571*57b5a4a6SAndroid Build Coastguard Worker} 572*57b5a4a6SAndroid Build Coastguard Worker 573*57b5a4a6SAndroid Build Coastguard Worker@Serializable 574*57b5a4a6SAndroid Build Coastguard Worker@SerialName("owned") 575*57b5a4a6SAndroid Build Coastguard Workerclass OwnedProject(override val name: String, val owner: String) : Project() 576*57b5a4a6SAndroid Build Coastguard Worker--> 577*57b5a4a6SAndroid Build Coastguard Worker 578*57b5a4a6SAndroid Build Coastguard Worker```kotlin 579*57b5a4a6SAndroid Build Coastguard Workerfun main() { 580*57b5a4a6SAndroid Build Coastguard Worker val data: Any = OwnedProject("kotlinx.coroutines", "kotlin") 581*57b5a4a6SAndroid Build Coastguard Worker println(format.encodeToString(PolymorphicSerializer(Any::class), data)) 582*57b5a4a6SAndroid Build Coastguard Worker} 583*57b5a4a6SAndroid Build Coastguard Worker``` 584*57b5a4a6SAndroid Build Coastguard Worker 585*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-14.kt). 586*57b5a4a6SAndroid Build Coastguard Worker 587*57b5a4a6SAndroid Build Coastguard WorkerWith the explicit serializer it works as before. 588*57b5a4a6SAndroid Build Coastguard Worker 589*57b5a4a6SAndroid Build Coastguard Worker```text 590*57b5a4a6SAndroid Build Coastguard Worker{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"} 591*57b5a4a6SAndroid Build Coastguard Worker``` 592*57b5a4a6SAndroid Build Coastguard Worker 593*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST --> 594*57b5a4a6SAndroid Build Coastguard Worker 595*57b5a4a6SAndroid Build Coastguard Worker### Explicitly marking polymorphic class properties 596*57b5a4a6SAndroid Build Coastguard Worker 597*57b5a4a6SAndroid Build Coastguard WorkerThe property of an interface type is implicitly considered polymorphic, since interfaces are all about runtime polymorphism. 598*57b5a4a6SAndroid Build Coastguard WorkerHowever, Kotlin Serialization does not compile a serializable class with a property of a non-serializable class type. 599*57b5a4a6SAndroid Build Coastguard WorkerIf we have a property of `Any` class or other non-serializable class, then we must explicitly provide its serialization 600*57b5a4a6SAndroid Build Coastguard Workerstrategy via the [`@Serializable`][Serializable] annotation as we saw in 601*57b5a4a6SAndroid Build Coastguard Workerthe [Specifying serializer on a property](serializers.md#specifying-serializer-on-a-property) section. 602*57b5a4a6SAndroid Build Coastguard WorkerTo specify a polymorphic serialization strategy of a property, the special-purpose [`@Polymorphic`][Polymorphic] 603*57b5a4a6SAndroid Build Coastguard Workerannotation is used. 604*57b5a4a6SAndroid Build Coastguard Worker 605*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE 606*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.* 607*57b5a4a6SAndroid Build Coastguard Worker 608*57b5a4a6SAndroid Build Coastguard Workerval module = SerializersModule { 609*57b5a4a6SAndroid Build Coastguard Worker polymorphic(Any::class) { 610*57b5a4a6SAndroid Build Coastguard Worker subclass(OwnedProject::class) 611*57b5a4a6SAndroid Build Coastguard Worker } 612*57b5a4a6SAndroid Build Coastguard Worker} 613*57b5a4a6SAndroid Build Coastguard Worker 614*57b5a4a6SAndroid Build Coastguard Workerval format = Json { serializersModule = module } 615*57b5a4a6SAndroid Build Coastguard Worker 616*57b5a4a6SAndroid Build Coastguard Workerinterface Project { 617*57b5a4a6SAndroid Build Coastguard Worker val name: String 618*57b5a4a6SAndroid Build Coastguard Worker} 619*57b5a4a6SAndroid Build Coastguard Worker 620*57b5a4a6SAndroid Build Coastguard Worker@Serializable 621*57b5a4a6SAndroid Build Coastguard Worker@SerialName("owned") 622*57b5a4a6SAndroid Build Coastguard Workerclass OwnedProject(override val name: String, val owner: String) : Project 623*57b5a4a6SAndroid Build Coastguard Worker--> 624*57b5a4a6SAndroid Build Coastguard Worker 625*57b5a4a6SAndroid Build Coastguard Worker```kotlin 626*57b5a4a6SAndroid Build Coastguard Worker@Serializable 627*57b5a4a6SAndroid Build Coastguard Workerclass Data( 628*57b5a4a6SAndroid Build Coastguard Worker @Polymorphic // the code does not compile without it 629*57b5a4a6SAndroid Build Coastguard Worker val project: Any 630*57b5a4a6SAndroid Build Coastguard Worker) 631*57b5a4a6SAndroid Build Coastguard Worker 632*57b5a4a6SAndroid Build Coastguard Workerfun main() { 633*57b5a4a6SAndroid Build Coastguard Worker val data = Data(OwnedProject("kotlinx.coroutines", "kotlin")) 634*57b5a4a6SAndroid Build Coastguard Worker println(format.encodeToString(data)) 635*57b5a4a6SAndroid Build Coastguard Worker} 636*57b5a4a6SAndroid Build Coastguard Worker``` 637*57b5a4a6SAndroid Build Coastguard Worker 638*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-15.kt). 639*57b5a4a6SAndroid Build Coastguard Worker 640*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST 641*57b5a4a6SAndroid Build Coastguard Worker{"project":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}} 642*57b5a4a6SAndroid Build Coastguard Worker--> 643*57b5a4a6SAndroid Build Coastguard Worker 644*57b5a4a6SAndroid Build Coastguard Worker### Registering multiple superclasses 645*57b5a4a6SAndroid Build Coastguard Worker 646*57b5a4a6SAndroid Build Coastguard WorkerWhen the same class gets serialized as a value of properties with different compile-time type from the list of 647*57b5a4a6SAndroid Build Coastguard Workerits superclasses, we must register it in the [SerializersModule] for each of its superclasses separately. 648*57b5a4a6SAndroid Build Coastguard WorkerIt is convenient to extract registration of all the subclasses into a separate function and 649*57b5a4a6SAndroid Build Coastguard Workeruse it for each superclass. You can use the following template to write it. 650*57b5a4a6SAndroid Build Coastguard Worker 651*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE 652*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.* 653*57b5a4a6SAndroid Build Coastguard Workerimport kotlin.reflect.KClass 654*57b5a4a6SAndroid Build Coastguard Worker--> 655*57b5a4a6SAndroid Build Coastguard Worker 656*57b5a4a6SAndroid Build Coastguard Worker```kotlin 657*57b5a4a6SAndroid Build Coastguard Workerval module = SerializersModule { 658*57b5a4a6SAndroid Build Coastguard Worker fun PolymorphicModuleBuilder<Project>.registerProjectSubclasses() { 659*57b5a4a6SAndroid Build Coastguard Worker subclass(OwnedProject::class) 660*57b5a4a6SAndroid Build Coastguard Worker } 661*57b5a4a6SAndroid Build Coastguard Worker polymorphic(Any::class) { registerProjectSubclasses() } 662*57b5a4a6SAndroid Build Coastguard Worker polymorphic(Project::class) { registerProjectSubclasses() } 663*57b5a4a6SAndroid Build Coastguard Worker} 664*57b5a4a6SAndroid Build Coastguard Worker``` 665*57b5a4a6SAndroid Build Coastguard Worker 666*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE 667*57b5a4a6SAndroid Build Coastguard Worker 668*57b5a4a6SAndroid Build Coastguard Workerval format = Json { serializersModule = module } 669*57b5a4a6SAndroid Build Coastguard Worker 670*57b5a4a6SAndroid Build Coastguard Workerinterface Project { 671*57b5a4a6SAndroid Build Coastguard Worker val name: String 672*57b5a4a6SAndroid Build Coastguard Worker} 673*57b5a4a6SAndroid Build Coastguard Worker 674*57b5a4a6SAndroid Build Coastguard Worker@Serializable 675*57b5a4a6SAndroid Build Coastguard Worker@SerialName("owned") 676*57b5a4a6SAndroid Build Coastguard Workerclass OwnedProject(override val name: String, val owner: String) : Project 677*57b5a4a6SAndroid Build Coastguard Worker 678*57b5a4a6SAndroid Build Coastguard Worker@Serializable 679*57b5a4a6SAndroid Build Coastguard Workerclass Data( 680*57b5a4a6SAndroid Build Coastguard Worker val project: Project, 681*57b5a4a6SAndroid Build Coastguard Worker @Polymorphic val any: Any 682*57b5a4a6SAndroid Build Coastguard Worker) 683*57b5a4a6SAndroid Build Coastguard Worker 684*57b5a4a6SAndroid Build Coastguard Workerfun main() { 685*57b5a4a6SAndroid Build Coastguard Worker val project = OwnedProject("kotlinx.coroutines", "kotlin") 686*57b5a4a6SAndroid Build Coastguard Worker val data = Data(project, project) 687*57b5a4a6SAndroid Build Coastguard Worker println(format.encodeToString(data)) 688*57b5a4a6SAndroid Build Coastguard Worker} 689*57b5a4a6SAndroid Build Coastguard Worker--> 690*57b5a4a6SAndroid Build Coastguard Worker 691*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-16.kt). 692*57b5a4a6SAndroid Build Coastguard Worker 693*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST 694*57b5a4a6SAndroid Build Coastguard Worker{"project":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"},"any":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}} 695*57b5a4a6SAndroid Build Coastguard Worker--> 696*57b5a4a6SAndroid Build Coastguard Worker 697*57b5a4a6SAndroid Build Coastguard Worker### Polymorphism and generic classes 698*57b5a4a6SAndroid Build Coastguard Worker 699*57b5a4a6SAndroid Build Coastguard WorkerGeneric subtypes for a serializable class require a special handling. Consider the following hierarchy. 700*57b5a4a6SAndroid Build Coastguard Worker 701*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE 702*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.* 703*57b5a4a6SAndroid Build Coastguard Worker--> 704*57b5a4a6SAndroid Build Coastguard Worker 705*57b5a4a6SAndroid Build Coastguard Worker```kotlin 706*57b5a4a6SAndroid Build Coastguard Worker@Serializable 707*57b5a4a6SAndroid Build Coastguard Workerabstract class Response<out T> 708*57b5a4a6SAndroid Build Coastguard Worker 709*57b5a4a6SAndroid Build Coastguard Worker@Serializable 710*57b5a4a6SAndroid Build Coastguard Worker@SerialName("OkResponse") 711*57b5a4a6SAndroid Build Coastguard Workerdata class OkResponse<out T>(val data: T) : Response<T>() 712*57b5a4a6SAndroid Build Coastguard Worker``` 713*57b5a4a6SAndroid Build Coastguard Worker 714*57b5a4a6SAndroid Build Coastguard WorkerKotlin Serialization does not have a builtin strategy to represent the actually provided argument type for the 715*57b5a4a6SAndroid Build Coastguard Workertype parameter `T` when serializing a property of the polymorphic type `OkResponse<T>`. We have to provide this 716*57b5a4a6SAndroid Build Coastguard Workerstrategy explicitly when defining the serializers module for the `Response`. In the below example we 717*57b5a4a6SAndroid Build Coastguard Workeruse `OkResponse.serializer(...)` to retrieve 718*57b5a4a6SAndroid Build Coastguard Workerthe [Plugin-generated generic serializer](serializers.md#plugin-generated-generic-serializer) of 719*57b5a4a6SAndroid Build Coastguard Workerthe `OkResponse` class and instantiate it with the [PolymorphicSerializer] instance with 720*57b5a4a6SAndroid Build Coastguard Worker`Any` class as its base. This way, we can serialize an instance of `OkResponse` with any `data` property that 721*57b5a4a6SAndroid Build Coastguard Workerwas polymorphically registered as a subtype of `Any`. 722*57b5a4a6SAndroid Build Coastguard Worker 723*57b5a4a6SAndroid Build Coastguard Worker```kotlin 724*57b5a4a6SAndroid Build Coastguard Workerval responseModule = SerializersModule { 725*57b5a4a6SAndroid Build Coastguard Worker polymorphic(Response::class) { 726*57b5a4a6SAndroid Build Coastguard Worker subclass(OkResponse.serializer(PolymorphicSerializer(Any::class))) 727*57b5a4a6SAndroid Build Coastguard Worker } 728*57b5a4a6SAndroid Build Coastguard Worker} 729*57b5a4a6SAndroid Build Coastguard Worker``` 730*57b5a4a6SAndroid Build Coastguard Worker 731*57b5a4a6SAndroid Build Coastguard Worker### Merging library serializers modules 732*57b5a4a6SAndroid Build Coastguard Worker 733*57b5a4a6SAndroid Build Coastguard WorkerWhen the application grows in size and splits into source code modules, 734*57b5a4a6SAndroid Build Coastguard Workerit may become inconvenient to store all class hierarchies in one serializers module. 735*57b5a4a6SAndroid Build Coastguard WorkerLet us add a library with the `Project` hierarchy to the code from the previous section. 736*57b5a4a6SAndroid Build Coastguard Worker 737*57b5a4a6SAndroid Build Coastguard Worker```kotlin 738*57b5a4a6SAndroid Build Coastguard Workerval projectModule = SerializersModule { 739*57b5a4a6SAndroid Build Coastguard Worker fun PolymorphicModuleBuilder<Project>.registerProjectSubclasses() { 740*57b5a4a6SAndroid Build Coastguard Worker subclass(OwnedProject::class) 741*57b5a4a6SAndroid Build Coastguard Worker } 742*57b5a4a6SAndroid Build Coastguard Worker polymorphic(Any::class) { registerProjectSubclasses() } 743*57b5a4a6SAndroid Build Coastguard Worker polymorphic(Project::class) { registerProjectSubclasses() } 744*57b5a4a6SAndroid Build Coastguard Worker} 745*57b5a4a6SAndroid Build Coastguard Worker``` 746*57b5a4a6SAndroid Build Coastguard Worker 747*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE 748*57b5a4a6SAndroid Build Coastguard Worker 749*57b5a4a6SAndroid Build Coastguard Worker@Serializable 750*57b5a4a6SAndroid Build Coastguard Workerabstract class Project { 751*57b5a4a6SAndroid Build Coastguard Worker abstract val name: String 752*57b5a4a6SAndroid Build Coastguard Worker} 753*57b5a4a6SAndroid Build Coastguard Worker 754*57b5a4a6SAndroid Build Coastguard Worker@Serializable 755*57b5a4a6SAndroid Build Coastguard Worker@SerialName("OwnedProject") 756*57b5a4a6SAndroid Build Coastguard Workerdata class OwnedProject(override val name: String, val owner: String) : Project() 757*57b5a4a6SAndroid Build Coastguard Worker--> 758*57b5a4a6SAndroid Build Coastguard Worker 759*57b5a4a6SAndroid Build Coastguard WorkerWe can compose those two modules together using the [plus] operator to merge them, 760*57b5a4a6SAndroid Build Coastguard Workerso that we can use them both in the same [Json] format instance. 761*57b5a4a6SAndroid Build Coastguard Worker 762*57b5a4a6SAndroid Build Coastguard Worker> You can also use the [include][SerializersModuleBuilder.include] function 763*57b5a4a6SAndroid Build Coastguard Worker> in the [SerializersModule {}][SerializersModule()] DSL. 764*57b5a4a6SAndroid Build Coastguard Worker 765*57b5a4a6SAndroid Build Coastguard Worker```kotlin 766*57b5a4a6SAndroid Build Coastguard Workerval format = Json { serializersModule = projectModule + responseModule } 767*57b5a4a6SAndroid Build Coastguard Worker```` 768*57b5a4a6SAndroid Build Coastguard Worker 769*57b5a4a6SAndroid Build Coastguard WorkerNow classes from both hierarchies can be serialized together and deserialized together. 770*57b5a4a6SAndroid Build Coastguard Worker 771*57b5a4a6SAndroid Build Coastguard Worker```kotlin 772*57b5a4a6SAndroid Build Coastguard Workerfun main() { 773*57b5a4a6SAndroid Build Coastguard Worker // both Response and Project are abstract and their concrete subtypes are being serialized 774*57b5a4a6SAndroid Build Coastguard Worker val data: Response<Project> = OkResponse(OwnedProject("kotlinx.serialization", "kotlin")) 775*57b5a4a6SAndroid Build Coastguard Worker val string = format.encodeToString(data) 776*57b5a4a6SAndroid Build Coastguard Worker println(string) 777*57b5a4a6SAndroid Build Coastguard Worker println(format.decodeFromString<Response<Project>>(string)) 778*57b5a4a6SAndroid Build Coastguard Worker} 779*57b5a4a6SAndroid Build Coastguard Worker 780*57b5a4a6SAndroid Build Coastguard Worker``` 781*57b5a4a6SAndroid Build Coastguard Worker 782*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-17.kt). 783*57b5a4a6SAndroid Build Coastguard Worker 784*57b5a4a6SAndroid Build Coastguard WorkerThe JSON that is being produced is deeply polymorphic. 785*57b5a4a6SAndroid Build Coastguard Worker 786*57b5a4a6SAndroid Build Coastguard Worker```text 787*57b5a4a6SAndroid Build Coastguard Worker{"type":"OkResponse","data":{"type":"OwnedProject","name":"kotlinx.serialization","owner":"kotlin"}} 788*57b5a4a6SAndroid Build Coastguard WorkerOkResponse(data=OwnedProject(name=kotlinx.serialization, owner=kotlin)) 789*57b5a4a6SAndroid Build Coastguard Worker``` 790*57b5a4a6SAndroid Build Coastguard Worker 791*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST --> 792*57b5a4a6SAndroid Build Coastguard Worker 793*57b5a4a6SAndroid Build Coastguard WorkerIf you're writing a library or shared module with an abstract class and some implementations of it, 794*57b5a4a6SAndroid Build Coastguard Workeryou can expose your own serializers module for your clients to use so that a client can combine your 795*57b5a4a6SAndroid Build Coastguard Workermodule with their modules. 796*57b5a4a6SAndroid Build Coastguard Worker 797*57b5a4a6SAndroid Build Coastguard Worker### Default polymorphic type handler for deserialization 798*57b5a4a6SAndroid Build Coastguard Worker 799*57b5a4a6SAndroid Build Coastguard WorkerWhat happens when we deserialize a subclass that was not registered? 800*57b5a4a6SAndroid Build Coastguard Worker 801*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE 802*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.* 803*57b5a4a6SAndroid Build Coastguard Worker 804*57b5a4a6SAndroid Build Coastguard Worker@Serializable 805*57b5a4a6SAndroid Build Coastguard Workerabstract class Project { 806*57b5a4a6SAndroid Build Coastguard Worker abstract val name: String 807*57b5a4a6SAndroid Build Coastguard Worker} 808*57b5a4a6SAndroid Build Coastguard Worker 809*57b5a4a6SAndroid Build Coastguard Worker@Serializable 810*57b5a4a6SAndroid Build Coastguard Worker@SerialName("OwnedProject") 811*57b5a4a6SAndroid Build Coastguard Workerdata class OwnedProject(override val name: String, val owner: String) : Project() 812*57b5a4a6SAndroid Build Coastguard Worker 813*57b5a4a6SAndroid Build Coastguard Workerval module = SerializersModule { 814*57b5a4a6SAndroid Build Coastguard Worker polymorphic(Project::class) { 815*57b5a4a6SAndroid Build Coastguard Worker subclass(OwnedProject::class) 816*57b5a4a6SAndroid Build Coastguard Worker } 817*57b5a4a6SAndroid Build Coastguard Worker} 818*57b5a4a6SAndroid Build Coastguard Worker 819*57b5a4a6SAndroid Build Coastguard Workerval format = Json { serializersModule = module } 820*57b5a4a6SAndroid Build Coastguard Worker--> 821*57b5a4a6SAndroid Build Coastguard Worker 822*57b5a4a6SAndroid Build Coastguard Worker```kotlin 823*57b5a4a6SAndroid Build Coastguard Workerfun main() { 824*57b5a4a6SAndroid Build Coastguard Worker println(format.decodeFromString<Project>(""" 825*57b5a4a6SAndroid Build Coastguard Worker {"type":"unknown","name":"example"} 826*57b5a4a6SAndroid Build Coastguard Worker """)) 827*57b5a4a6SAndroid Build Coastguard Worker} 828*57b5a4a6SAndroid Build Coastguard Worker``` 829*57b5a4a6SAndroid Build Coastguard Worker 830*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-18.kt). 831*57b5a4a6SAndroid Build Coastguard Worker 832*57b5a4a6SAndroid Build Coastguard WorkerWe get the following exception. 833*57b5a4a6SAndroid Build Coastguard Worker 834*57b5a4a6SAndroid Build Coastguard Worker```text 835*57b5a4a6SAndroid Build Coastguard WorkerException in thread "main" kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 0: Serializer for subclass 'unknown' is not found in the polymorphic scope of 'Project' at path: $ 836*57b5a4a6SAndroid Build Coastguard WorkerCheck if class with serial name 'unknown' exists and serializer is registered in a corresponding SerializersModule. 837*57b5a4a6SAndroid Build Coastguard Worker``` 838*57b5a4a6SAndroid Build Coastguard Worker 839*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST LINES_START --> 840*57b5a4a6SAndroid Build Coastguard Worker 841*57b5a4a6SAndroid Build Coastguard WorkerWhen reading a flexible input we might want to provide some default behavior in this case. For example, 842*57b5a4a6SAndroid Build Coastguard Workerwe can have a `BasicProject` subtype to represent all kinds of unknown `Project` subtypes. 843*57b5a4a6SAndroid Build Coastguard Worker 844*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE 845*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.* 846*57b5a4a6SAndroid Build Coastguard Worker--> 847*57b5a4a6SAndroid Build Coastguard Worker 848*57b5a4a6SAndroid Build Coastguard Worker```kotlin 849*57b5a4a6SAndroid Build Coastguard Worker@Serializable 850*57b5a4a6SAndroid Build Coastguard Workerabstract class Project { 851*57b5a4a6SAndroid Build Coastguard Worker abstract val name: String 852*57b5a4a6SAndroid Build Coastguard Worker} 853*57b5a4a6SAndroid Build Coastguard Worker 854*57b5a4a6SAndroid Build Coastguard Worker@Serializable 855*57b5a4a6SAndroid Build Coastguard Workerdata class BasicProject(override val name: String, val type: String): Project() 856*57b5a4a6SAndroid Build Coastguard Worker 857*57b5a4a6SAndroid Build Coastguard Worker@Serializable 858*57b5a4a6SAndroid Build Coastguard Worker@SerialName("OwnedProject") 859*57b5a4a6SAndroid Build Coastguard Workerdata class OwnedProject(override val name: String, val owner: String) : Project() 860*57b5a4a6SAndroid Build Coastguard Worker``` 861*57b5a4a6SAndroid Build Coastguard Worker 862*57b5a4a6SAndroid Build Coastguard WorkerWe register a default deserializer handler using the [`defaultDeserializer`][PolymorphicModuleBuilder.defaultDeserializer] function in 863*57b5a4a6SAndroid Build Coastguard Workerthe [`polymorphic { ... }`][PolymorphicModuleBuilder] DSL that defines a strategy which maps the `type` string from the input 864*57b5a4a6SAndroid Build Coastguard Workerto the [deserialization strategy][DeserializationStrategy]. In the below example we don't use the type, 865*57b5a4a6SAndroid Build Coastguard Workerbut always return the [Plugin-generated serializer](serializers.md#plugin-generated-serializer) 866*57b5a4a6SAndroid Build Coastguard Workerof the `BasicProject` class. 867*57b5a4a6SAndroid Build Coastguard Worker 868*57b5a4a6SAndroid Build Coastguard Worker```kotlin 869*57b5a4a6SAndroid Build Coastguard Workerval module = SerializersModule { 870*57b5a4a6SAndroid Build Coastguard Worker polymorphic(Project::class) { 871*57b5a4a6SAndroid Build Coastguard Worker subclass(OwnedProject::class) 872*57b5a4a6SAndroid Build Coastguard Worker defaultDeserializer { BasicProject.serializer() } 873*57b5a4a6SAndroid Build Coastguard Worker } 874*57b5a4a6SAndroid Build Coastguard Worker} 875*57b5a4a6SAndroid Build Coastguard Worker``` 876*57b5a4a6SAndroid Build Coastguard Worker 877*57b5a4a6SAndroid Build Coastguard WorkerUsing this module we can now deserialize both instances of the registered `OwnedProject` and 878*57b5a4a6SAndroid Build Coastguard Workerany unregistered one. 879*57b5a4a6SAndroid Build Coastguard Worker 880*57b5a4a6SAndroid Build Coastguard Worker```kotlin 881*57b5a4a6SAndroid Build Coastguard Workerval format = Json { serializersModule = module } 882*57b5a4a6SAndroid Build Coastguard Worker 883*57b5a4a6SAndroid Build Coastguard Workerfun main() { 884*57b5a4a6SAndroid Build Coastguard Worker println(format.decodeFromString<List<Project>>(""" 885*57b5a4a6SAndroid Build Coastguard Worker [ 886*57b5a4a6SAndroid Build Coastguard Worker {"type":"unknown","name":"example"}, 887*57b5a4a6SAndroid Build Coastguard Worker {"type":"OwnedProject","name":"kotlinx.serialization","owner":"kotlin"} 888*57b5a4a6SAndroid Build Coastguard Worker ] 889*57b5a4a6SAndroid Build Coastguard Worker """)) 890*57b5a4a6SAndroid Build Coastguard Worker} 891*57b5a4a6SAndroid Build Coastguard Worker``` 892*57b5a4a6SAndroid Build Coastguard Worker 893*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-19.kt). 894*57b5a4a6SAndroid Build Coastguard Worker 895*57b5a4a6SAndroid Build Coastguard WorkerNotice, how `BasicProject` had also captured the specified type key in its `type` property. 896*57b5a4a6SAndroid Build Coastguard Worker 897*57b5a4a6SAndroid Build Coastguard Worker```text 898*57b5a4a6SAndroid Build Coastguard Worker[BasicProject(name=example, type=unknown), OwnedProject(name=kotlinx.serialization, owner=kotlin)] 899*57b5a4a6SAndroid Build Coastguard Worker``` 900*57b5a4a6SAndroid Build Coastguard Worker 901*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST --> 902*57b5a4a6SAndroid Build Coastguard Worker 903*57b5a4a6SAndroid Build Coastguard WorkerWe used a plugin-generated serializer as a default serializer, implying that 904*57b5a4a6SAndroid Build Coastguard Workerthe structure of the "unknown" data is known in advance. In a real-world API it's rarely the case. 905*57b5a4a6SAndroid Build Coastguard WorkerFor that purpose a custom, less-structured serializer is needed. You will see the example of such serializer in the future section 906*57b5a4a6SAndroid Build Coastguard Workeron [Maintaining custom JSON attributes](json.md#maintaining-custom-json-attributes). 907*57b5a4a6SAndroid Build Coastguard Worker 908*57b5a4a6SAndroid Build Coastguard Worker### Default polymorphic type handler for serialization 909*57b5a4a6SAndroid Build Coastguard Worker 910*57b5a4a6SAndroid Build Coastguard WorkerSometimes you need to dynamically choose which serializer to use for a polymorphic type based on the instance, for example if you 911*57b5a4a6SAndroid Build Coastguard Workerdon't have access to the full type hierarchy, or if it changes a lot. For this situation, you can register a default serializer. 912*57b5a4a6SAndroid Build Coastguard Worker 913*57b5a4a6SAndroid Build Coastguard Worker<!--- INCLUDE 914*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.descriptors.* 915*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.encoding.* 916*57b5a4a6SAndroid Build Coastguard Workerimport kotlinx.serialization.modules.* 917*57b5a4a6SAndroid Build Coastguard Worker--> 918*57b5a4a6SAndroid Build Coastguard Worker 919*57b5a4a6SAndroid Build Coastguard Worker```kotlin 920*57b5a4a6SAndroid Build Coastguard Workerinterface Animal { 921*57b5a4a6SAndroid Build Coastguard Worker} 922*57b5a4a6SAndroid Build Coastguard Worker 923*57b5a4a6SAndroid Build Coastguard Workerinterface Cat : Animal { 924*57b5a4a6SAndroid Build Coastguard Worker val catType: String 925*57b5a4a6SAndroid Build Coastguard Worker} 926*57b5a4a6SAndroid Build Coastguard Worker 927*57b5a4a6SAndroid Build Coastguard Workerinterface Dog : Animal { 928*57b5a4a6SAndroid Build Coastguard Worker val dogType: String 929*57b5a4a6SAndroid Build Coastguard Worker} 930*57b5a4a6SAndroid Build Coastguard Worker 931*57b5a4a6SAndroid Build Coastguard Workerprivate class CatImpl : Cat { 932*57b5a4a6SAndroid Build Coastguard Worker override val catType: String = "Tabby" 933*57b5a4a6SAndroid Build Coastguard Worker} 934*57b5a4a6SAndroid Build Coastguard Worker 935*57b5a4a6SAndroid Build Coastguard Workerprivate class DogImpl : Dog { 936*57b5a4a6SAndroid Build Coastguard Worker override val dogType: String = "Husky" 937*57b5a4a6SAndroid Build Coastguard Worker} 938*57b5a4a6SAndroid Build Coastguard Worker 939*57b5a4a6SAndroid Build Coastguard Workerobject AnimalProvider { 940*57b5a4a6SAndroid Build Coastguard Worker fun createCat(): Cat = CatImpl() 941*57b5a4a6SAndroid Build Coastguard Worker fun createDog(): Dog = DogImpl() 942*57b5a4a6SAndroid Build Coastguard Worker} 943*57b5a4a6SAndroid Build Coastguard Worker``` 944*57b5a4a6SAndroid Build Coastguard Worker 945*57b5a4a6SAndroid Build Coastguard WorkerWe register a default serializer handler using the [`polymorphicDefaultSerializer`][SerializersModuleBuilder.polymorphicDefaultSerializer] function in 946*57b5a4a6SAndroid Build Coastguard Workerthe [`SerializersModule { ... }`][SerializersModuleBuilder] DSL that defines a strategy which takes an instance of the base class and 947*57b5a4a6SAndroid Build Coastguard Workerprovides a [serialization strategy][SerializationStrategy]. In the below example we use a `when` block to check the type of the 948*57b5a4a6SAndroid Build Coastguard Workerinstance, without ever having to refer to the private implementation classes. 949*57b5a4a6SAndroid Build Coastguard Worker 950*57b5a4a6SAndroid Build Coastguard Worker```kotlin 951*57b5a4a6SAndroid Build Coastguard Workerval module = SerializersModule { 952*57b5a4a6SAndroid Build Coastguard Worker polymorphicDefaultSerializer(Animal::class) { instance -> 953*57b5a4a6SAndroid Build Coastguard Worker @Suppress("UNCHECKED_CAST") 954*57b5a4a6SAndroid Build Coastguard Worker when (instance) { 955*57b5a4a6SAndroid Build Coastguard Worker is Cat -> CatSerializer as SerializationStrategy<Animal> 956*57b5a4a6SAndroid Build Coastguard Worker is Dog -> DogSerializer as SerializationStrategy<Animal> 957*57b5a4a6SAndroid Build Coastguard Worker else -> null 958*57b5a4a6SAndroid Build Coastguard Worker } 959*57b5a4a6SAndroid Build Coastguard Worker } 960*57b5a4a6SAndroid Build Coastguard Worker} 961*57b5a4a6SAndroid Build Coastguard Worker 962*57b5a4a6SAndroid Build Coastguard Workerobject CatSerializer : SerializationStrategy<Cat> { 963*57b5a4a6SAndroid Build Coastguard Worker override val descriptor = buildClassSerialDescriptor("Cat") { 964*57b5a4a6SAndroid Build Coastguard Worker element<String>("catType") 965*57b5a4a6SAndroid Build Coastguard Worker } 966*57b5a4a6SAndroid Build Coastguard Worker 967*57b5a4a6SAndroid Build Coastguard Worker override fun serialize(encoder: Encoder, value: Cat) { 968*57b5a4a6SAndroid Build Coastguard Worker encoder.encodeStructure(descriptor) { 969*57b5a4a6SAndroid Build Coastguard Worker encodeStringElement(descriptor, 0, value.catType) 970*57b5a4a6SAndroid Build Coastguard Worker } 971*57b5a4a6SAndroid Build Coastguard Worker } 972*57b5a4a6SAndroid Build Coastguard Worker} 973*57b5a4a6SAndroid Build Coastguard Worker 974*57b5a4a6SAndroid Build Coastguard Workerobject DogSerializer : SerializationStrategy<Dog> { 975*57b5a4a6SAndroid Build Coastguard Worker override val descriptor = buildClassSerialDescriptor("Dog") { 976*57b5a4a6SAndroid Build Coastguard Worker element<String>("dogType") 977*57b5a4a6SAndroid Build Coastguard Worker } 978*57b5a4a6SAndroid Build Coastguard Worker 979*57b5a4a6SAndroid Build Coastguard Worker override fun serialize(encoder: Encoder, value: Dog) { 980*57b5a4a6SAndroid Build Coastguard Worker encoder.encodeStructure(descriptor) { 981*57b5a4a6SAndroid Build Coastguard Worker encodeStringElement(descriptor, 0, value.dogType) 982*57b5a4a6SAndroid Build Coastguard Worker } 983*57b5a4a6SAndroid Build Coastguard Worker } 984*57b5a4a6SAndroid Build Coastguard Worker} 985*57b5a4a6SAndroid Build Coastguard Worker``` 986*57b5a4a6SAndroid Build Coastguard Worker 987*57b5a4a6SAndroid Build Coastguard WorkerUsing this module we can now serialize instances of `Cat` and `Dog`. 988*57b5a4a6SAndroid Build Coastguard Worker 989*57b5a4a6SAndroid Build Coastguard Worker```kotlin 990*57b5a4a6SAndroid Build Coastguard Workerval format = Json { serializersModule = module } 991*57b5a4a6SAndroid Build Coastguard Worker 992*57b5a4a6SAndroid Build Coastguard Workerfun main() { 993*57b5a4a6SAndroid Build Coastguard Worker println(format.encodeToString<Animal>(AnimalProvider.createCat())) 994*57b5a4a6SAndroid Build Coastguard Worker} 995*57b5a4a6SAndroid Build Coastguard Worker``` 996*57b5a4a6SAndroid Build Coastguard Worker 997*57b5a4a6SAndroid Build Coastguard Worker> You can get the full code [here](../guide/example/example-poly-20.kt) 998*57b5a4a6SAndroid Build Coastguard Worker 999*57b5a4a6SAndroid Build Coastguard Worker```text 1000*57b5a4a6SAndroid Build Coastguard Worker{"type":"Cat","catType":"Tabby"} 1001*57b5a4a6SAndroid Build Coastguard Worker``` 1002*57b5a4a6SAndroid Build Coastguard Worker 1003*57b5a4a6SAndroid Build Coastguard Worker 1004*57b5a4a6SAndroid Build Coastguard Worker<!--- TEST --> 1005*57b5a4a6SAndroid Build Coastguard Worker 1006*57b5a4a6SAndroid Build Coastguard Worker--- 1007*57b5a4a6SAndroid Build Coastguard Worker 1008*57b5a4a6SAndroid Build Coastguard WorkerThe next chapter covers [JSON features](json.md). 1009*57b5a4a6SAndroid Build Coastguard Worker 1010*57b5a4a6SAndroid Build Coastguard Worker<!--- MODULE /kotlinx-serialization-core --> 1011*57b5a4a6SAndroid Build Coastguard Worker<!--- INDEX kotlinx-serialization-core/kotlinx.serialization --> 1012*57b5a4a6SAndroid Build Coastguard Worker 1013*57b5a4a6SAndroid Build Coastguard Worker[SerialName]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serial-name/index.html 1014*57b5a4a6SAndroid Build Coastguard Worker[PolymorphicSerializer]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-polymorphic-serializer/index.html 1015*57b5a4a6SAndroid Build Coastguard Worker[Serializable]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serializable/index.html 1016*57b5a4a6SAndroid Build Coastguard Worker[Polymorphic]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-polymorphic/index.html 1017*57b5a4a6SAndroid Build Coastguard Worker[DeserializationStrategy]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-deserialization-strategy/index.html 1018*57b5a4a6SAndroid Build Coastguard Worker[SerializationStrategy]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization/-serialization-strategy/index.html 1019*57b5a4a6SAndroid Build Coastguard Worker 1020*57b5a4a6SAndroid Build Coastguard Worker<!--- INDEX kotlinx-serialization-core/kotlinx.serialization.modules --> 1021*57b5a4a6SAndroid Build Coastguard Worker 1022*57b5a4a6SAndroid Build Coastguard Worker[SerializersModule]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module/index.html 1023*57b5a4a6SAndroid Build Coastguard Worker[SerializersModule()]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module.html 1024*57b5a4a6SAndroid Build Coastguard Worker[_polymorphic]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/polymorphic.html 1025*57b5a4a6SAndroid Build Coastguard Worker[subclass]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/subclass.html 1026*57b5a4a6SAndroid Build Coastguard Worker[plus]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/plus.html 1027*57b5a4a6SAndroid Build Coastguard Worker[SerializersModuleBuilder.include]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module-builder/include.html 1028*57b5a4a6SAndroid Build Coastguard Worker[PolymorphicModuleBuilder.defaultDeserializer]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/-polymorphic-module-builder/default-deserializer.html 1029*57b5a4a6SAndroid Build Coastguard Worker[PolymorphicModuleBuilder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/-polymorphic-module-builder/index.html 1030*57b5a4a6SAndroid Build Coastguard Worker[SerializersModuleBuilder.polymorphicDefaultSerializer]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module-builder/polymorphic-default-serializer.html 1031*57b5a4a6SAndroid Build Coastguard Worker[SerializersModuleBuilder]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.modules/-serializers-module-builder/index.html 1032*57b5a4a6SAndroid Build Coastguard Worker 1033*57b5a4a6SAndroid Build Coastguard Worker<!--- MODULE /kotlinx-serialization-json --> 1034*57b5a4a6SAndroid Build Coastguard Worker<!--- INDEX kotlinx-serialization-json/kotlinx.serialization.json --> 1035*57b5a4a6SAndroid Build Coastguard Worker 1036*57b5a4a6SAndroid Build Coastguard Worker[Json.encodeToString]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json/encode-to-string.html 1037*57b5a4a6SAndroid Build Coastguard Worker[Json]: https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-json/kotlinx.serialization.json/-json/index.html 1038*57b5a4a6SAndroid Build Coastguard Worker 1039*57b5a4a6SAndroid Build Coastguard Worker<!--- END --> 1040*57b5a4a6SAndroid Build Coastguard Worker 1041