@@ -17,6 +17,7 @@ In this chapter we'll take a look at serializers in more detail, and we'll see h
17
17
* [ Using top-level serializer function] ( #using-top-level-serializer-function )
18
18
* [ Custom serializers] ( #custom-serializers )
19
19
* [ Primitive serializer] ( #primitive-serializer )
20
+ * [ Delegating serializers] ( #delegating-serializers )
20
21
* [ Composite serializer via surrogate] ( #composite-serializer-via-surrogate )
21
22
* [ Hand-written composite serializer] ( #hand-written-composite-serializer )
22
23
* [ Sequential decoding protocol (experimental)] ( #sequential-decoding-protocol-experimental )
@@ -377,6 +378,72 @@ Both `Color` properties are serialized as strings.
377
378
378
379
<!-- - TEST -->
379
380
381
+ ### Delegating serializers
382
+
383
+ In the previous example, we represented the ` Color ` class as a string.
384
+ String is considered to be a primitive type, therefore we used ` PrimitiveClassDescriptor ` and specialized ` encodeString ` method.
385
+ Now let's see what our actions would be if we have to serialize ` Color ` as another non-primitive type, let's say ` IntArray ` .
386
+
387
+ An implementation of [ KSerializer] for our original ` Color ` class is going to perform a conversion between
388
+ ` Color ` and ` IntArray ` , but delegate the actual serialization logic to the ` IntArraySerializer `
389
+ using [ encodeSerializableValue] [ Encoder.encodeSerializableValue ] and
390
+ [ decodeSerializableValue] [ Decoder.decodeSerializableValue ] .
391
+
392
+ ``` kotlin
393
+ import kotlinx.serialization.builtins.IntArraySerializer
394
+
395
+ class ColorIntArraySerializer : KSerializer <Color > {
396
+ private val delegateSerializer = IntArraySerializer ()
397
+ override val descriptor = SerialDescriptor (" Color" , delegateSerializer.descriptor)
398
+
399
+ override fun serialize (encoder : Encoder , value : Color ) {
400
+ val data = intArrayOf(
401
+ (value.rgb shr 16 ) and 0xFF ,
402
+ (value.rgb shr 8 ) and 0xFF ,
403
+ value.rgb and 0xFF
404
+ )
405
+ encoder.encodeSerializableValue(delegateSerializer, data)
406
+ }
407
+
408
+ override fun deserialize (decoder : Decoder ): Color {
409
+ val array = decoder.decodeSerializableValue(delegateSerializer)
410
+ return Color ((array[0 ] shl 16 ) or (array[1 ] shl 8 ) or array[2 ])
411
+ }
412
+ }
413
+ ```
414
+
415
+ Note that we can't use default ` Color.serializer().descriptor ` here because formats that rely
416
+ on the schema may think that we would call ` encodeInt ` instead of ` encodeSerializableValue ` .
417
+ Neither we can use ` IntArraySerializer().descriptor ` directly — otherwise, formats that handle int arrays specially
418
+ can't tell if ` value ` is really a ` IntArray ` or a ` Color ` . Don't worry, this optimization would still kick in
419
+ when serializing actual underlying int array.
420
+
421
+ > Example of how format can treat arrays specially is shown in the [ formats guide] ( formats.md#format-specific-types ) .
422
+
423
+ Now we can use the serializer:
424
+
425
+ ``` kotlin
426
+ @Serializable(with = ColorIntArraySerializer ::class )
427
+ class Color (val rgb : Int )
428
+
429
+ fun main () {
430
+ val green = Color (0x00ff00 )
431
+ println (Json .encodeToString(green))
432
+ }
433
+ ```
434
+
435
+ As you can see, such array representation is not very useful in JSON,
436
+ but may save some space when used with a ` ByteArray ` and a binary format.
437
+
438
+ > You can get the full code [ here] ( ../guide/example/example-serializer-10.kt ) .
439
+
440
+ ``` text
441
+ [0,255,0]
442
+ ```
443
+
444
+ <!-- - TEST -->
445
+
446
+
380
447
### Composite serializer via surrogate
381
448
382
449
Now our challenge is to get ` Color ` serialized so that it is represented in JSON as if it is a class
@@ -403,11 +470,9 @@ private class ColorSurrogate(val r: Int, val g: Int, val b: Int) {
403
470
Now we can use the ` ColorSurrogate.serializer() ` function to retrieve a plugin-generated serializer for the
404
471
surrogate class.
405
472
406
- An implementation of [ KSerializer] for our original ` Color ` class is going to perform a conversion between
407
- ` Color ` and ` ColorSurrogate ` , but delegate the actual serialization logic to the ` ColorSurrogate.serializer() `
408
- using [ encodeSerializableValue] [ Encoder.encodeSerializableValue ] and
409
- [ decodeSerializableValue] [ Decoder.decodeSerializableValue ] , fully reusing an automatically
410
- generated [ SerialDescriptor] for the surrogate.
473
+ We can use the same approach as in [ delegating serializer] ( #delegating-serializers ) , but this time,
474
+ we are fully reusing an automatically
475
+ generated [ SerialDescriptor] for the surrogate because it should be indistinguishable from the original.
411
476
412
477
``` kotlin
413
478
object ColorSerializer : KSerializer<Color> {
@@ -441,7 +506,7 @@ fun main() {
441
506
}
442
507
-->
443
508
444
- > You can get the full code [ here] ( ../guide/example/example-serializer-10 .kt ) .
509
+ > You can get the full code [ here] ( ../guide/example/example-serializer-11 .kt ) .
445
510
446
511
``` text
447
512
{"r":0,"g":255,"b":0}
@@ -535,7 +600,7 @@ fun main() {
535
600
}
536
601
```
537
602
538
- > You can get the full code [here](../guide/example/example-serializer-11 .kt).
603
+ > You can get the full code [here](../guide/example/example-serializer-12 .kt).
539
604
540
605
As before, we got the `Color` class represented as a JSON object with three keys:
541
606
@@ -609,7 +674,7 @@ fun main() {
609
674
}
610
675
-->
611
676
612
- > You can get the full code [here](../guide/example/example-serializer-12 .kt).
677
+ > You can get the full code [here](../guide/example/example-serializer-13 .kt).
613
678
614
679
<!--- TEST
615
680
{"r":0,"g":255,"b":0}
@@ -656,7 +721,7 @@ fun main() {
656
721
}
657
722
```
658
723
659
- > You can get the full code [here](.. / guide/ example/ example- serializer- 13 .kt).
724
+ > You can get the full code [here](.. / guide/ example/ example- serializer- 14 .kt).
660
725
661
726
```text
662
727
1455494400000
@@ -694,7 +759,7 @@ fun main() {
694
759
}
695
760
```
696
761
697
- > You can get the full code [here](.. / guide/ example/ example- serializer- 14 .kt).
762
+ > You can get the full code [here](.. / guide/ example/ example- serializer- 15 .kt).
698
763
699
764
The `stableReleaseDate` property is serialized with the serialization strategy that we specified for it:
700
765
@@ -737,7 +802,7 @@ fun main() {
737
802
println (Json .encodeToString(data))
738
803
}
739
804
```
740
- > You can get the full code [here](.. / guide/ example/ example- serializer- 15 .kt).
805
+ > You can get the full code [here](.. / guide/ example/ example- serializer- 16 .kt).
741
806
742
807
```text
743
808
{" name" : " Kotlin" ," stableReleaseDate" : 1455494400000 }
@@ -785,7 +850,7 @@ fun main() {
785
850
}
786
851
```
787
852
788
- > You can get the full code [here](../guide/example/example-serializer-16 .kt).
853
+ > You can get the full code [here](../guide/example/example-serializer-17 .kt).
789
854
790
855
The resulting JSON looks like the `Project` class was serialized directly.
791
856
@@ -849,7 +914,7 @@ fun main() {
849
914
To actually serialize this class we must provide the corresponding context when calling the `encodeToXxx`/`decodeFromXxx`
850
915
functions. Without it we' ll get a " Serializer for class 'Date' is not found" exception.
851
916
852
- > See [here](.. / guide/ example/ example- serializer- 17 .kt) for an example that produces that exception.
917
+ > See [here](.. / guide/ example/ example- serializer- 18 .kt) for an example that produces that exception.
853
918
854
919
< ! -- - TEST LINES_START
855
920
Exception in thread " main" kotlinx.serialization.SerializationException : Serializer for class ' Date' is not found.
@@ -908,7 +973,7 @@ fun main() {
908
973
}
909
974
```
910
975
911
- > You can get the full code [here](.. / guide/ example/ example- serializer- 18 .kt).
976
+ > You can get the full code [here](.. / guide/ example/ example- serializer- 19 .kt).
912
977
```text
913
978
{" name" : " Kotlin" ," stableReleaseDate" : 1455494400000 }
914
979
```
@@ -967,7 +1032,7 @@ fun main() {
967
1032
}
968
1033
```
969
1034
970
- > You can get the full code [here](.. / guide/ example/ example- serializer- 19 .kt).
1035
+ > You can get the full code [here](.. / guide/ example/ example- serializer- 20 .kt).
971
1036
972
1037
This gets all the `Project ` properties serialized:
973
1038
@@ -1008,7 +1073,7 @@ fun main() {
1008
1073
}
1009
1074
```
1010
1075
1011
- > You can get the full code [here](.. / guide/ example/ example- serializer- 20 .kt).
1076
+ > You can get the full code [here](.. / guide/ example/ example- serializer- 21 .kt).
1012
1077
1013
1078
The output is shown below.
1014
1079
0 commit comments