@@ -18,6 +18,7 @@ stable, these are currently experimental features of Kotlin Serialization.
1818 * [ Integer types] ( #integer-types )
1919 * [ Lists as repeated fields] ( #lists-as-repeated-fields )
2020 * [ Packed fields] ( #packed-fields )
21+ * [ Oneof field (experimental)] ( #oneof-field-experimental )
2122 * [ ProtoBuf schema generator (experimental)] ( #protobuf-schema-generator-experimental )
2223* [ Properties (experimental)] ( #properties-experimental )
2324* [ Custom formats (experimental)] ( #custom-formats-experimental )
@@ -435,6 +436,65 @@ Per the standard packed fields can only be used on primitive numeric types. The
435436Per the [ format description] ( https://developers.google.com/protocol-buffers/docs/encoding#packed ) the parser ignores
436437the annotation, but rather reads list in either packed or repeated format.
437438
439+ ### Oneof field (experimental)
440+
441+ Kotlin Serialization ` ProtoBuf ` format supports [ oneof] ( https://protobuf.dev/programming-guides/proto2/#oneof ) fields
442+ base on the [ Polymorphism] ( polymorphism.md ) .
443+
444+ You can declare a property of your class to be ` oneof ` by following the contracts:
445+
446+ * Declare an interface, or abstract class, in represent of the ` oneof ` group.
447+ * Declare the property with the type added above, annotated with ` @ProtoOneOf(ids) `
448+ with all possible proto numbers, not ` @ProtoNumber ` .
449+ * Declare subclasses from the type with ** only one property** each per the oneof group elements.
450+ * Annotated the subclasses with ` @ProtoNumber ` on the class declaration, not the property,
451+ per the oneof group elements and ` @ProtoOneOf(ids) ` above.
452+
453+ <!-- - INCLUDE
454+ import kotlinx.serialization.*
455+ import kotlinx.serialization.protobuf.*
456+ -->
457+
458+ ``` kotlin
459+ @Serializable
460+ data class Data (
461+ @ProtoNumber(1 ) val name : String ,
462+ @ProtoOneOf(2 , 3 ) val phone : IPhoneType ,
463+ )
464+ @Serializable sealed interface IPhoneType
465+ @Serializable @ProtoNumber(2 ) @JvmInline value class HomePhone (val number : String ): IPhoneType
466+ @Serializable @ProtoNumber(3 ) data class WorkPhone (val number : String ): IPhoneType
467+
468+ fun main () {
469+ val dataTom = Data (" Tom" , HomePhone (" 123" ))
470+ val stringTom = ProtoBuf .encodeToHexString(dataTom)
471+ val dataJerry = Data (" Jerry" , WorkPhone (" 789" ))
472+ val stringJerry = ProtoBuf .encodeToHexString(dataJerry)
473+ println (stringTom)
474+ println (stringJerry)
475+ println (ProtoBuf .decodeFromHexString<Data >(stringTom))
476+ println (ProtoBuf .decodeFromHexString<Data >(stringJerry))
477+ }
478+ ```
479+
480+ > You can get the full code [ here] ( ../guide/example/example-formats-08.kt ) .
481+
482+ ``` text
483+ 0a03546f6d1203313233
484+ 0a054a657272791a03373839
485+ Data(name=Tom, phone=HomePhone(number=123))
486+ Data(name=Jerry, phone=WorkPhone(number=789))
487+ ```
488+
489+ <!-- - TEST -->
490+
491+ In [ ProtoBuf diagnostic mode] ( https://protogen.marcgravell.com/decode ) the first 2 lines on output is equivalent to
492+
493+ ```
494+ Field #1: 0A String Length = 3, Hex = 03, UTF8 = "Tom" Field #2: 12 String Length = 3, Hex = 03, UTF8 = "123"
495+ Field #1: 0A String Length = 5, Hex = 05, UTF8 = "Jerry" Field #3: 1A String Length = 3, Hex = 03, UTF8 = "789"
496+ ```
497+
438498### ProtoBuf schema generator (experimental)
439499
440500As mentioned above, when working with protocol buffers you usually use a ".proto" file and a code generator for your
@@ -467,15 +527,15 @@ fun main() {
467527 println (schemas)
468528}
469529```
470- > You can get the full code [ here] ( ../guide/example/example-formats-08 .kt ) .
530+ > You can get the full code [ here] ( ../guide/example/example-formats-09 .kt ) .
471531
472532Which would output as follows.
473533
474534``` text
475535syntax = "proto2";
476536
477537
478- // serial name 'example.exampleFormats08 .SampleData'
538+ // serial name 'example.exampleFormats09 .SampleData'
479539message SampleData {
480540 required int64 amount = 1;
481541 optional string description = 2;
@@ -519,7 +579,7 @@ fun main() {
519579}
520580```
521581
522- > You can get the full code [ here] ( ../guide/example/example-formats-09 .kt ) .
582+ > You can get the full code [ here] ( ../guide/example/example-formats-10 .kt ) .
523583
524584The resulting map has dot-separated keys representing keys of the nested objects.
525585
@@ -599,7 +659,7 @@ fun main() {
599659}
600660```
601661
602- > You can get the full code [ here] ( ../guide/example/example-formats-10 .kt ) .
662+ > You can get the full code [ here] ( ../guide/example/example-formats-11 .kt ) .
603663
604664As a result, we got all the primitive values in our object graph visited and put into a list
605665in _ serial_ order.
@@ -701,7 +761,7 @@ fun main() {
701761}
702762```
703763
704- > You can get the full code [ here] ( ../guide/example/example-formats-11 .kt ) .
764+ > You can get the full code [ here] ( ../guide/example/example-formats-12 .kt ) .
705765
706766Now we can convert a list of primitives back to an object tree.
707767
@@ -792,7 +852,7 @@ fun main() {
792852}
793853-->
794854
795- > You can get the full code [ here] ( ../guide/example/example-formats-12 .kt ) .
855+ > You can get the full code [ here] ( ../guide/example/example-formats-13 .kt ) .
796856
797857<!-- - TEST
798858[kotlinx.serialization, kotlin, 9000]
@@ -899,7 +959,7 @@ fun main() {
899959}
900960```
901961
902- > You can get the full code [ here] ( ../guide/example/example-formats-13 .kt ) .
962+ > You can get the full code [ here] ( ../guide/example/example-formats-14 .kt ) .
903963
904964We see the size of the list added to the result, letting the decoder know where to stop.
905965
@@ -1011,7 +1071,7 @@ fun main() {
10111071
10121072```
10131073
1014- > You can get the full code [ here] ( ../guide/example/example-formats-14 .kt ) .
1074+ > You can get the full code [ here] ( ../guide/example/example-formats-15 .kt ) .
10151075
10161076In the output we see how not-null` !! ` and ` NULL ` marks are used.
10171077
@@ -1139,7 +1199,7 @@ fun main() {
11391199}
11401200```
11411201
1142- > You can get the full code [ here] ( ../guide/example/example-formats-15 .kt ) .
1202+ > You can get the full code [ here] ( ../guide/example/example-formats-16 .kt ) .
11431203
11441204As we can see, the result is a dense binary format that only contains the data that is being serialized.
11451205It can be easily tweaked for any kind of domain-specific compact encoding.
@@ -1333,7 +1393,7 @@ fun main() {
13331393}
13341394```
13351395
1336- > You can get the full code [ here] ( ../guide/example/example-formats-16 .kt ) .
1396+ > You can get the full code [ here] ( ../guide/example/example-formats-17 .kt ) .
13371397
13381398As we can see, our custom byte array format is being used, with the compact encoding of its size in one byte.
13391399
0 commit comments