How to master polymorphism and custom serializers in kotlinx.serialization

Sascha Huth
Wise Engineering
Published in
2 min readJul 2, 2019

--

Photo by Jakub Kapusnak

If you’re migrating from GSON or any other serialization library to kotlinx.serialization (KXS), chances are that you have to find a solution to replace your custom type adapters. That could be because you implement polymorphic response models, or require some other fancy customization when converting between JSON and Kotlin.

There are two main ways of dealing with that in KXS, so let’s go through both of them and see what’s best for your use case.

1. The @Polymorphic annotation

This is an implicit, descriptive approach for adding subclass awareness to our serializer.

has blogged about this before.

As a quick example, let’s define a Fruit class with two subclasses — Apple and Orange — and add the required annotations:

Now you have to teach your KXS Json instance about the polymorphic type by passing it in a SerializersModule:

Let’s write a quick test for the serialization and deserialization. Note that we can use Kotlin’s raw string notation to avoid having to escape quotes in the JSON string 💪:

And that’s it 🎉. Quite straight-forward, but there’s a couple of downsides with that approach:

  • It only works when objects are self-contained, meaning they have their class defined as one of their fields
  • It only works when objects can be classified by a single field, not by a combination of fields or some other logic
  • You can only define one classDiscriminator per JsonConfiguration, meaning we need a new Json instance if that field name is different in other API responses.

If you want to overcome those limitations, you need a more customized solution:

2. A custom @Serializer

This one gives you full control over the serialization process. You have to adapt your models to add the @Serializer annotation and explicitly define the itemType:

Note that you don’t have to overwrite serialize() and deserialize() if you only need one of them (read-only APIs etc.).

You can see that this solution is a bit more verbose than the polymorphic annotation, but definitely more powerful.

You can instantiate the KXS Json object the same way as before, just without the polymorphic block. The tests from the previous section will also pass successfully ✅.

Please let me know in the comments if you have any issues or questions.

By the way: At TransferWise, we’re not so much about apples and oranges. But we did need to write a custom serializer for the different items in our app’s activity feed — so that our customers can see what they send, spend and receive.

If you’d like to help us move to kotlinx.serialization or solve other interesting challenges: we are hiring 🤓.

P.S. Interested to join us? We’re hiring. Check out our open Engineering roles.

--

--

Sascha Huth
Wise Engineering

Building software for Androids and humans @TransferWise