-
Notifications
You must be signed in to change notification settings - Fork 625
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support using an integer as the class/case discriminator in polymorphic serialization #2587
base: dev
Are you sure you want to change the base?
Conversation
…rs, and serializers modules for serializing type numbers in polymorphic serialization without any support from the serialization plugin yet
…sses to polymorphic numbers See commit 3289fb2.
…edSerializer` that causes the tests to break
Some miscellaneous changes: 1. Add a `getSerialPolymorphicNumberByBaseClass` function in `SerialDescriptor` to throw the appropriate exception. 1. Add `defaultDeserializerForNumber` which was missing in `PolymorphicModuleBuilder`.
…ion, and update an annotation property name The corresponding commit: huanshankeji/kotlin@9860724
…Class` into `PluginGeneratedSerialDescriptor` where it belongs and add some more tests in `SerialPolymorphicNumberTest` (which fail for now)
…phicNumber` with `@SerialInfo` to be stored in `SerialDescriptor.annotations` and refactor related code Main changes: 1. Extract common lazy properties in `CommonSerialDescriptor` and make both `PluginGeneratedSerialDescriptor` and `SerialDescriptorImpl` inherit it. 1. Support serial polymorphic numbers with JSON's custom implementations in `AbstractJsonTreeEncoder`, `StreamingJsonEncoder`, and `DynamicObjectEncoder` while adapting the `encodePolymorphically` and `decodeSerializableValuePolymorphic` functions. 1. Revert gradle.properties since there is no need to update the compiler plugin anymore. 1. Make all tests pass in `SerialPolymorphicNumberTest` and copy it into the Protobuf module and adapt.
…ents and reverting some unnecessary changes
More details to discussCurrent API designThe current design is like this: @Serializable
@UseSerialPolymorphicNumbers
sealed class Sealed {
@Serializable
@SerialPolymorphicNumber(Sealed::class, 1)
object Case : Sealed()
} Json.encodeToString<Sealed>(Sealed.Case)
Json.decodeFromString<Sealed>("""{"type":1}""") One marks the classes with Alternatives of implementation details and designsThe implemented code is a prototype. Here are improvements and alternatives to be discussed. Alternative names for "serial polymorphic number"There can be alternative names for the word "serial polymorphic number". For example, these are what I can think of:
FunctionsThere are 2 properties The added function names may have better alternatives too. Some more possible unimplemented APIsAn independent version of the
|
There is a lot of added complexity and special casing in this code. The same outcome could be achieved with a custom implementation of a polymorphic serializer (that maps between numbers and serial names), that can be marked as serializer for the base type. There are then only a few additions needed from serialization itself:
Note also that your numbers system is a challenge as the numbers need to be unique (possibly within the entire program) if they are to completely replace serial names (on types). |
Number is ambiguous here, I typically use |
@pdvrieze Thanks for the reply.
This is indeed the approach I am currently adopting in my projects, where I need to specify two-way
This looks good, but I think it doesn't help that much if such information is only available at runtime and such exhaustiveness checks are not available at compile time.
Yeah this looks like a general and elegant way.
In the current implementation, the numbers are only unique in the scope of one certain base class (which is necessary). That's why a If you mean in the scope of one base class, the number of a subclass should be different in different places, I think we can support it in the |
@recursive-rat4 Yeah perhaps "integer" is a better word. I still think using an |
…er` and make it work See Kotlin#2598.
As for now, this library serializes the class/type of a subclass using a
serialName
in polymorphic serialization, which can be overridden with the@SerialName
annotation. I'd like to propose supporting using a number and requiring subclasses to use numbers in polymorphic serialization, as it shortens the size of the serialized message greatly, especially in a binary format such as Protobuf.When choosing to use a binary format such as Protobuf, one of the biggest concerns is shortening the size of serialized messages. In such a case serializing a fully qualified name of a subclass by default doesn't make much sense, as the binary format such as Protobuf compared to a readable string format as JSON reduces the serialized size of other fields by more than 50%, while a class discriminator takes the same size and takes up the majority of the message size, which defies the whole point. An alternative might be to override the serial name with a short name or a single letter, but IMO, still, the message is longer and it's less elegant than using a number.