Skip to content

Commit ce74cc8

Browse files
committed
Update the documentation with example code (and knit).
1 parent 12781ad commit ce74cc8

13 files changed

+205
-179
lines changed

docs/polymorphism.md

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ In this chapter we'll see how Kotlin Serialization deals with polymorphic class
1919
* [Open polymorphism](#open-polymorphism)
2020
* [Registered subclasses](#registered-subclasses)
2121
* [Serializing interfaces](#serializing-interfaces)
22+
* [Registering sealed children as subclasses](#registering-sealed-children-as-subclasses)
2223
* [Property of an interface type](#property-of-an-interface-type)
2324
* [Static parent type lookup for polymorphism](#static-parent-type-lookup-for-polymorphism)
2425
* [Explicitly marking polymorphic class properties](#explicitly-marking-polymorphic-class-properties)
@@ -421,6 +422,60 @@ note that this is will remain open serialization, and the sealed parent serializ
421422
In addition, it is not valid if the hierarchy contains open (not sealed) polymorphic children (this will result in
422423
an error at runtime). In other words all children/descendants must be either concrete or sealed.
423424

425+
<!--- TEST -->
426+
427+
<!--- INCLUDE
428+
import kotlinx.serialization.modules.*
429+
-->
430+
431+
```kotlin
432+
interface Base
433+
434+
@Serializable
435+
sealed interface Sub: Base
436+
437+
@Serializable
438+
class Sub1(val data: String): Sub
439+
440+
val module1 = SerializersModule {
441+
polymorphic(Base::class) {
442+
subclassesOfSealed(Sub.serializer())
443+
}
444+
}
445+
446+
val format1 = Json { serializersModule = module1 }
447+
```
448+
449+
Alternatively the convenience overload allows specifying the sealed type as type parameter.
450+
451+
```kotlin
452+
val module2 = SerializersModule {
453+
polymorphic(Base::class) {
454+
subclassesOfSealed<Sub>()
455+
}
456+
}
457+
458+
val format2 = Json { serializersModule = module2 }
459+
```
460+
461+
Now if we declare `data` with the type of `Base` we can simply call `format.encodeToString` as before.
462+
```kotlin
463+
464+
fun main() {
465+
val data: Base = Sub1("kotlin")
466+
println(format1.encodeToString(data))
467+
println(format2.encodeToString(data))
468+
}
469+
```
470+
471+
```text
472+
{"type":"example.examplePoly11.Sub1","data":"kotlin"}
473+
{"type":"example.examplePoly11.Sub1","data":"kotlin"}
474+
```
475+
476+
> You can get the full code [here](../guide/example/example-poly-11.kt).
477+
478+
424479
<!--- TEST LINES_START -->
425480

426481
### Property of an interface type
@@ -458,7 +513,7 @@ fun main() {
458513
}
459514
```
460515

461-
> You can get the full code [here](../guide/example/example-poly-11.kt).
516+
> You can get the full code [here](../guide/example/example-poly-12.kt).
462517
463518
As long as we've registered the actual subtype of the interface that is being serialized in
464519
the [SerializersModule] of our `format`, we get it working at runtime.
@@ -503,7 +558,7 @@ fun main() {
503558
}
504559
```
505560

506-
> You can get the full code [here](../guide/example/example-poly-12.kt).
561+
> You can get the full code [here](../guide/example/example-poly-13.kt).
507562
508563
We get the exception.
509564

@@ -551,7 +606,7 @@ fun main() {
551606
}
552607
```
553608

554-
> You can get the full code [here](../guide/example/example-poly-13.kt).
609+
> You can get the full code [here](../guide/example/example-poly-14.kt).
555610
556611
However, `Any` is a class and it is not serializable:
557612

@@ -593,7 +648,7 @@ fun main() {
593648
}
594649
```
595650

596-
> You can get the full code [here](../guide/example/example-poly-14.kt).
651+
> You can get the full code [here](../guide/example/example-poly-15.kt).
597652
598653
With the explicit serializer it works as before.
599654

@@ -646,7 +701,7 @@ fun main() {
646701
}
647702
```
648703

649-
> You can get the full code [here](../guide/example/example-poly-15.kt).
704+
> You can get the full code [here](../guide/example/example-poly-16.kt).
650705
651706
<!--- TEST
652707
{"project":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}}
@@ -699,7 +754,7 @@ fun main() {
699754
}
700755
-->
701756

702-
> You can get the full code [here](../guide/example/example-poly-16.kt).
757+
> You can get the full code [here](../guide/example/example-poly-17.kt).
703758
704759
<!--- TEST
705760
{"project":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"},"any":{"type":"owned","name":"kotlinx.coroutines","owner":"kotlin"}}
@@ -790,7 +845,7 @@ fun main() {
790845

791846
```
792847

793-
> You can get the full code [here](../guide/example/example-poly-17.kt).
848+
> You can get the full code [here](../guide/example/example-poly-18.kt).
794849
795850
The JSON that is being produced is deeply polymorphic.
796851

@@ -838,7 +893,7 @@ fun main() {
838893
}
839894
```
840895

841-
> You can get the full code [here](../guide/example/example-poly-18.kt).
896+
> You can get the full code [here](../guide/example/example-poly-19.kt).
842897
843898
We get the following exception.
844899

@@ -901,7 +956,7 @@ fun main() {
901956
}
902957
```
903958

904-
> You can get the full code [here](../guide/example/example-poly-19.kt).
959+
> You can get the full code [here](../guide/example/example-poly-20.kt).
905960
906961
Notice, how `BasicProject` had also captured the specified type key in its `type` property.
907962

@@ -1005,7 +1060,7 @@ fun main() {
10051060
}
10061061
```
10071062

1008-
> You can get the full code [here](../guide/example/example-poly-20.kt)
1063+
> You can get the full code [here](../guide/example/example-poly-21.kt)
10091064
10101065
```text
10111066
{"type":"Cat","catType":"Tabby"}

docs/serialization-guide.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ Once the project is set up, we can start serializing some classes.
9797
* <a name='open-polymorphism'></a>[Open polymorphism](polymorphism.md#open-polymorphism)
9898
* <a name='registered-subclasses'></a>[Registered subclasses](polymorphism.md#registered-subclasses)
9999
* <a name='serializing-interfaces'></a>[Serializing interfaces](polymorphism.md#serializing-interfaces)
100+
* <a name='registering-sealed-children-as-subclasses'></a>[Registering sealed children as subclasses](polymorphism.md#registering-sealed-children-as-subclasses)
100101
* <a name='property-of-an-interface-type'></a>[Property of an interface type](polymorphism.md#property-of-an-interface-type)
101102
* <a name='static-parent-type-lookup-for-polymorphism'></a>[Static parent type lookup for polymorphism](polymorphism.md#static-parent-type-lookup-for-polymorphism)
102103
* <a name='explicitly-marking-polymorphic-class-properties'></a>[Explicitly marking polymorphic class properties](polymorphism.md#explicitly-marking-polymorphic-class-properties)

guide/example/example-poly-11.kt

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,33 @@ import kotlinx.serialization.json.*
66

77
import kotlinx.serialization.modules.*
88

9-
val module = SerializersModule {
10-
polymorphic(Project::class) {
11-
subclass(OwnedProject::class)
12-
}
9+
interface Base
10+
11+
@Serializable
12+
sealed interface Sub: Base
13+
14+
@Serializable
15+
class Sub1(val data: String): Sub
16+
17+
val module1 = SerializersModule {
18+
polymorphic(Base::class) {
19+
subclassesOfSealed(Sub.serializer())
20+
}
1321
}
1422

15-
val format = Json { serializersModule = module }
23+
val format1 = Json { serializersModule = module1 }
1624

17-
interface Project {
18-
val name: String
25+
val module2 = SerializersModule {
26+
polymorphic(Base::class) {
27+
subclassesOfSealed<Sub>()
28+
}
1929
}
2030

21-
@Serializable
22-
@SerialName("owned")
23-
class OwnedProject(override val name: String, val owner: String) : Project
31+
val format2 = Json { serializersModule = module2 }
2432

25-
@Serializable
26-
class Data(val project: Project) // Project is an interface
2733

2834
fun main() {
29-
val data = Data(OwnedProject("kotlinx.coroutines", "kotlin"))
30-
println(format.encodeToString(data))
31-
}
35+
val data: Base = Sub1("kotlin")
36+
println(format1.encodeToString(data))
37+
println(format2.encodeToString(data))
38+
}

guide/example/example-poly-12.kt

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,18 @@ val module = SerializersModule {
1414

1515
val format = Json { serializersModule = module }
1616

17-
@Serializable
18-
abstract class Project {
19-
abstract val name: String
17+
interface Project {
18+
val name: String
2019
}
21-
20+
2221
@Serializable
2322
@SerialName("owned")
24-
class OwnedProject(override val name: String, val owner: String) : Project()
23+
class OwnedProject(override val name: String, val owner: String) : Project
24+
25+
@Serializable
26+
class Data(val project: Project) // Project is an interface
2527

2628
fun main() {
27-
val data: Any = OwnedProject("kotlinx.coroutines", "kotlin")
29+
val data = Data(OwnedProject("kotlinx.coroutines", "kotlin"))
2830
println(format.encodeToString(data))
29-
}
31+
}

guide/example/example-poly-13.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import kotlinx.serialization.json.*
77
import kotlinx.serialization.modules.*
88

99
val module = SerializersModule {
10-
polymorphic(Any::class) {
10+
polymorphic(Project::class) {
1111
subclass(OwnedProject::class)
1212
}
1313
}
14+
1415
val format = Json { serializersModule = module }
1516

1617
@Serializable

guide/example/example-poly-14.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ val module = SerializersModule {
1111
subclass(OwnedProject::class)
1212
}
1313
}
14-
1514
val format = Json { serializersModule = module }
1615

1716
@Serializable
@@ -25,5 +24,5 @@ class OwnedProject(override val name: String, val owner: String) : Project()
2524

2625
fun main() {
2726
val data: Any = OwnedProject("kotlinx.coroutines", "kotlin")
28-
println(format.encodeToString(PolymorphicSerializer(Any::class), data))
27+
println(format.encodeToString(data))
2928
}

guide/example/example-poly-15.kt

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,16 @@ val module = SerializersModule {
1414

1515
val format = Json { serializersModule = module }
1616

17-
interface Project {
18-
val name: String
17+
@Serializable
18+
abstract class Project {
19+
abstract val name: String
1920
}
20-
21+
2122
@Serializable
2223
@SerialName("owned")
23-
class OwnedProject(override val name: String, val owner: String) : Project
24-
25-
@Serializable
26-
class Data(
27-
@Polymorphic // the code does not compile without it
28-
val project: Any
29-
)
24+
class OwnedProject(override val name: String, val owner: String) : Project()
3025

3126
fun main() {
32-
val data = Data(OwnedProject("kotlinx.coroutines", "kotlin"))
33-
println(format.encodeToString(data))
34-
}
27+
val data: Any = OwnedProject("kotlinx.coroutines", "kotlin")
28+
println(format.encodeToString(PolymorphicSerializer(Any::class), data))
29+
}

guide/example/example-poly-16.kt

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,12 @@ import kotlinx.serialization.*
55
import kotlinx.serialization.json.*
66

77
import kotlinx.serialization.modules.*
8-
import kotlin.reflect.KClass
98

109
val module = SerializersModule {
11-
fun PolymorphicModuleBuilder<Project>.registerProjectSubclasses() {
10+
polymorphic(Any::class) {
1211
subclass(OwnedProject::class)
1312
}
14-
polymorphic(Any::class) { registerProjectSubclasses() }
15-
polymorphic(Project::class) { registerProjectSubclasses() }
16-
}
13+
}
1714

1815
val format = Json { serializersModule = module }
1916

@@ -27,12 +24,11 @@ class OwnedProject(override val name: String, val owner: String) : Project
2724

2825
@Serializable
2926
class Data(
30-
val project: Project,
31-
@Polymorphic val any: Any
27+
@Polymorphic // the code does not compile without it
28+
val project: Any
3229
)
3330

3431
fun main() {
35-
val project = OwnedProject("kotlinx.coroutines", "kotlin")
36-
val data = Data(project, project)
32+
val data = Data(OwnedProject("kotlinx.coroutines", "kotlin"))
3733
println(format.encodeToString(data))
38-
}
34+
}

guide/example/example-poly-17.kt

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,46 +3,34 @@ package example.examplePoly17
33

44
import kotlinx.serialization.*
55
import kotlinx.serialization.json.*
6-
76
import kotlinx.serialization.modules.*
87

9-
@Serializable
10-
abstract class Response<out T>
11-
12-
@Serializable
13-
@SerialName("OkResponse")
14-
data class OkResponse<out T>(val data: T) : Response<T>()
15-
16-
val responseModule = SerializersModule {
17-
polymorphic(Response::class) {
18-
subclass(OkResponse.serializer(PolymorphicSerializer(Any::class)))
19-
}
20-
}
21-
22-
val projectModule = SerializersModule {
8+
val module = SerializersModule {
239
fun PolymorphicModuleBuilder<Project>.registerProjectSubclasses() {
2410
subclass(OwnedProject::class)
2511
}
2612
polymorphic(Any::class) { registerProjectSubclasses() }
2713
polymorphic(Project::class) { registerProjectSubclasses() }
28-
}
14+
}
2915

30-
@Serializable
31-
abstract class Project {
32-
abstract val name: String
16+
val format = Json { serializersModule = module }
17+
18+
interface Project {
19+
val name: String
3320
}
34-
21+
3522
@Serializable
36-
@SerialName("OwnedProject")
37-
data class OwnedProject(override val name: String, val owner: String) : Project()
23+
@SerialName("owned")
24+
class OwnedProject(override val name: String, val owner: String) : Project
3825

39-
val format = Json { serializersModule = projectModule + responseModule }
26+
@Serializable
27+
class Data(
28+
val project: Project,
29+
@Polymorphic val any: Any
30+
)
4031

4132
fun main() {
42-
// both Response and Project are abstract and their concrete subtypes are being serialized
43-
val data: Response<Project> = OkResponse(OwnedProject("kotlinx.serialization", "kotlin"))
44-
val string = format.encodeToString(data)
45-
println(string)
46-
println(format.decodeFromString<Response<Project>>(string))
47-
}
48-
33+
val project = OwnedProject("kotlinx.coroutines", "kotlin")
34+
val data = Data(project, project)
35+
println(format.encodeToString(data))
36+
}

0 commit comments

Comments
 (0)