@@ -144,7 +144,7 @@ class OwnedProject(override val name: String, val owner: String) : Project()
144144
145145fun main () {
146146 val data: Project = OwnedProject (" kotlinx.coroutines" , " kotlin" )
147- println (Json .encodeToString(data))
147+ println (Json .encodeToString(data)) // Serializing data of compile-time type Project
148148}
149149```
150150
@@ -159,6 +159,45 @@ A `type` key is added to the resulting JSON object as a _discriminator_.
159159
160160<!-- - TEST -->
161161
162+ Pay attention to the small, but very important detail in the above example that is related to [ Static types] ( #static-types ) :
163+ the ` val data ` property has a compile-time type of ` Project ` , even though its run-time type is ` OwnedProject ` .
164+ When serializing polymorphic class hierarchies you must ensure that the compile-time type of the serialized object
165+ is a polymorphic one, not a concrete one.
166+
167+ Let us see what happens if the example is slightly changed, so that the compile-time of the object that is being
168+ serialized is ` OwnedProject ` (the same as its run-time type).
169+
170+ ``` kotlin
171+ @Serializable
172+ sealed class Project {
173+ abstract val name: String
174+ }
175+
176+ @Serializable
177+ class OwnedProject (override val name : String , val owner : String ) : Project()
178+
179+ fun main () {
180+ val data = OwnedProject (" kotlinx.coroutines" , " kotlin" ) // data: OwnedProject here
181+ println (Json .encodeToString(data)) // Serializing data of compile-time type OwnedProject
182+ }
183+ ```
184+
185+ > You can get the full code [ here] ( ../guide/example/example-poly-05.kt ) .
186+
187+ The type of ` OwnedProject ` is concrete and is not polymorphic, thus the ` type `
188+ discriminator property is not emitted into the resulting JSON.
189+
190+ ``` text
191+ {"name":"kotlinx.coroutines","owner":"kotlin"}
192+ ```
193+
194+ <!-- - TEST -->
195+
196+ In general, Kotlin serialization is designed to work correctly only when the compile-time type used during serialization
197+ is the same one as the compile-time type used during deserialization. You can always specify the type explicitly
198+ when calling serialization functions. The previous example can be corrected to use ` Project ` type for serialization
199+ by calling ` Json.encodeToString<Project>(data) ` .
200+
162201### Custom subclass serial name
163202
164203A value of the ` type ` key is a fully qualified class name by default. We can put [ SerialName] annotation onto
@@ -180,7 +219,7 @@ fun main() {
180219}
181220```
182221
183- > You can get the full code [ here] ( ../guide/example/example-poly-05 .kt ) .
222+ > You can get the full code [ here] ( ../guide/example/example-poly-06 .kt ) .
184223
185224This way we can have a stable _ serial name_ that is not affected by the class's name in the source code.
186225
@@ -215,7 +254,7 @@ fun main() {
215254}
216255```
217256
218- > You can get the full code [ here] ( ../guide/example/example-poly-06 .kt ) .
257+ > You can get the full code [ here] ( ../guide/example/example-poly-07 .kt ) .
219258
220259The properties of the superclass are serialized before the properties of the subclass.
221260
@@ -250,12 +289,12 @@ fun main() {
250289}
251290```
252291
253- > You can get the full code [ here] ( ../guide/example/example-poly-07 .kt ) .
292+ > You can get the full code [ here] ( ../guide/example/example-poly-08 .kt ) .
254293
255294An object serializes as an empty class, also using its fully-qualified class name as type by default:
256295
257296``` text
258- [{"type":"example.examplePoly07 .EmptyResponse"},{"type":"example.examplePoly07 .TextResponse","text":"OK"}]
297+ [{"type":"example.examplePoly08 .EmptyResponse"},{"type":"example.examplePoly08 .TextResponse","text":"OK"}]
259298```
260299
261300<!-- - TEST -->
@@ -308,7 +347,7 @@ fun main() {
308347}
309348```
310349
311- > You can get the full code [ here] ( ../guide/example/example-poly-08 .kt ) .
350+ > You can get the full code [ here] ( ../guide/example/example-poly-09 .kt ) .
312351
313352This additional configuration makes our code work just as it worked with a sealed class in
314353the [ Sealed classes] ( #sealed-classes ) section, but here subclasses can be spread arbitrarily throughout the code.
@@ -361,7 +400,7 @@ fun main() {
361400}
362401```
363402
364- > You can get the full code [ here] ( ../guide/example/example-poly-09 .kt ) .
403+ > You can get the full code [ here] ( ../guide/example/example-poly-10 .kt ) .
365404
366405``` text
367406{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}
@@ -404,7 +443,7 @@ fun main() {
404443}
405444```
406445
407- > You can get the full code [ here] ( ../guide/example/example-poly-10 .kt ) .
446+ > You can get the full code [ here] ( ../guide/example/example-poly-11 .kt ) .
408447
409448As long as we've registered the actual subtype of the interface that is being serialized in
410449the [ SerializersModule] of our ` format ` , we get it working at runtime.
@@ -449,7 +488,7 @@ fun main() {
449488}
450489```
451490
452- > You can get the full code [ here] ( ../guide/example/example-poly-11 .kt ) .
491+ > You can get the full code [ here] ( ../guide/example/example-poly-12 .kt ) .
453492
454493We get the exception.
455494
@@ -497,7 +536,7 @@ fun main() {
497536}
498537```
499538
500- > You can get the full code [ here] ( ../guide/example/example-poly-12 .kt ) .
539+ > You can get the full code [ here] ( ../guide/example/example-poly-13 .kt ) .
501540
502541However, the ` Any ` is a class and it is not serializable:
503542
@@ -539,7 +578,7 @@ fun main() {
539578}
540579```
541580
542- > You can get the full code [ here] ( ../guide/example/example-poly-13 .kt ) .
581+ > You can get the full code [ here] ( ../guide/example/example-poly-14 .kt ) .
543582
544583With the explicit serializer it works as before.
545584
@@ -592,7 +631,7 @@ fun main() {
592631}
593632```
594633
595- > You can get the full code [ here] ( ../guide/example/example-poly-14 .kt ) .
634+ > You can get the full code [ here] ( ../guide/example/example-poly-15 .kt ) .
596635
597636<!-- - TEST
598637{"project":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}}
@@ -645,7 +684,7 @@ fun main() {
645684}
646685-->
647686
648- > You can get the full code [ here] ( ../guide/example/example-poly-15 .kt ) .
687+ > You can get the full code [ here] ( ../guide/example/example-poly-16 .kt ) .
649688
650689<!-- - TEST
651690{"project":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"},"any":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}}
@@ -736,7 +775,7 @@ fun main() {
736775
737776```
738777
739- > You can get the full code [ here] ( ../guide/example/example-poly-16 .kt ) .
778+ > You can get the full code [ here] ( ../guide/example/example-poly-17 .kt ) .
740779
741780The JSON that is being produced is deeply polymorphic.
742781
@@ -784,7 +823,7 @@ fun main() {
784823}
785824```
786825
787- > You can get the full code [ here] ( ../guide/example/example-poly-17 .kt ) .
826+ > You can get the full code [ here] ( ../guide/example/example-poly-18 .kt ) .
788827
789828We get the following exception.
790829
@@ -846,7 +885,7 @@ fun main() {
846885}
847886```
848887
849- > You can get the full code [ here] ( ../guide/example/example-poly-18 .kt ) .
888+ > You can get the full code [ here] ( ../guide/example/example-poly-19 .kt ) .
850889
851890Notice, how ` BasicProject ` had also captured the specified type key in its ` type ` property.
852891
0 commit comments