@@ -144,7 +144,7 @@ class OwnedProject(override val name: String, val owner: String) : Project()
144
144
145
145
fun main () {
146
146
val data: Project = OwnedProject (" kotlinx.coroutines" , " kotlin" )
147
- println (Json .encodeToString(data))
147
+ println (Json .encodeToString(data)) // Serializing data of compile-time type Project
148
148
}
149
149
```
150
150
@@ -159,6 +159,45 @@ A `type` key is added to the resulting JSON object as a _discriminator_.
159
159
160
160
<!-- - TEST -->
161
161
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
+
162
201
### Custom subclass serial name
163
202
164
203
A 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() {
180
219
}
181
220
```
182
221
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 ) .
184
223
185
224
This way we can have a stable _ serial name_ that is not affected by the class's name in the source code.
186
225
@@ -215,7 +254,7 @@ fun main() {
215
254
}
216
255
```
217
256
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 ) .
219
258
220
259
The properties of the superclass are serialized before the properties of the subclass.
221
260
@@ -250,12 +289,12 @@ fun main() {
250
289
}
251
290
```
252
291
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 ) .
254
293
255
294
An object serializes as an empty class, also using its fully-qualified class name as type by default:
256
295
257
296
``` text
258
- [{"type":"example.examplePoly07 .EmptyResponse"},{"type":"example.examplePoly07 .TextResponse","text":"OK"}]
297
+ [{"type":"example.examplePoly08 .EmptyResponse"},{"type":"example.examplePoly08 .TextResponse","text":"OK"}]
259
298
```
260
299
261
300
<!-- - TEST -->
@@ -308,7 +347,7 @@ fun main() {
308
347
}
309
348
```
310
349
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 ) .
312
351
313
352
This additional configuration makes our code work just as it worked with a sealed class in
314
353
the [ Sealed classes] ( #sealed-classes ) section, but here subclasses can be spread arbitrarily throughout the code.
@@ -361,7 +400,7 @@ fun main() {
361
400
}
362
401
```
363
402
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 ) .
365
404
366
405
``` text
367
406
{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}
@@ -404,7 +443,7 @@ fun main() {
404
443
}
405
444
```
406
445
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 ) .
408
447
409
448
As long as we've registered the actual subtype of the interface that is being serialized in
410
449
the [ SerializersModule] of our ` format ` , we get it working at runtime.
@@ -449,7 +488,7 @@ fun main() {
449
488
}
450
489
```
451
490
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 ) .
453
492
454
493
We get the exception.
455
494
@@ -497,7 +536,7 @@ fun main() {
497
536
}
498
537
```
499
538
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 ) .
501
540
502
541
However, the ` Any ` is a class and it is not serializable:
503
542
@@ -539,7 +578,7 @@ fun main() {
539
578
}
540
579
```
541
580
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 ) .
543
582
544
583
With the explicit serializer it works as before.
545
584
@@ -592,7 +631,7 @@ fun main() {
592
631
}
593
632
```
594
633
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 ) .
596
635
597
636
<!-- - TEST
598
637
{"project":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}}
@@ -645,7 +684,7 @@ fun main() {
645
684
}
646
685
-->
647
686
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 ) .
649
688
650
689
<!-- - TEST
651
690
{"project":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"},"any":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}}
@@ -736,7 +775,7 @@ fun main() {
736
775
737
776
```
738
777
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 ) .
740
779
741
780
The JSON that is being produced is deeply polymorphic.
742
781
@@ -784,7 +823,7 @@ fun main() {
784
823
}
785
824
```
786
825
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 ) .
788
827
789
828
We get the following exception.
790
829
@@ -846,7 +885,7 @@ fun main() {
846
885
}
847
886
```
848
887
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 ) .
850
889
851
890
Notice, how ` BasicProject ` had also captured the specified type key in its ` type ` property.
852
891
0 commit comments