Recently, I was working on a project in which I need to work with a lot of enums. When working with enums I need to serialize and deserialize the enum values with Kotlinx Serialization library. I gathered a couple of cool ways for enum serialization and deserialization with Kotlinx Serialization library.

To find out the basics of Kotlinx Serialization check out the following article.

Let’s take look at them one by one.

Simple Enum Serialization & Deserialization With Kotlinx Serialization

Serialization and Deserialization of enum class is a bit more complicated but in this article, you’ll find a cut-paste recipe. Now let’s say I have this following CardType enum class which represents different types of cards.

@Serializable(with = CardTypeSerializer::class) enum class CardType { GOLD, SILVER, PLATINUM }

You see I’m adding the @Serializable annotation to CardType enum. Well, that’s because the Kotlinx Serializer doesn’t know how to serialize the enum classes. That’s why we’re giving instructions to use CardTypeSerializer instead of default serializer.

Now we need to write our own serialization technique for CardType enum class.

@Serializer(forClass = CardType::class) // 1 object CardTypeSerializer { override val descriptor: SerialDescriptor get() = StringDescriptor // 2 override fun deserialize(decoder: Decoder): CardType { // 3 return CardType.valueOf(decoder.decodeString().toUpperCase()) } override fun serialize(encoder: Encoder, obj: CardType) { // 4 encoder.encodeString(obj.name.toLowerCase()) } }

Here’s the step-by-step explanation of the above code.

Giving the instructions to serialization plugin to turn this class into serializer for the specified class. In our case, we’re specifically telling that this serializer is only for CardType enum class by adding forClass property. Picking up the StringDescriptor for encoding and decoding the enum class. Parse the encoded json into CardType enum class. Convert the enum into to string using the value encoder.

Now the only thing left to do is to test our enum class serialization.

fun main() { val platinumCardJson = Json.stringify(CardTypeSerializer, CardType.PLATINUM) val platinum = Json.parse(CardTypeSerializer, platinumCardJson) println(platinumCardJson) println(platinum) } // Output of the above code "platinum" PLATINUM

Cool! that’s what we wanting to achieve enum classes serialization and deserialization right.

Custom Name For Enum Class Serialization & Deserialization with CommonEnumSerializer

It’s a quite common case when deserialization of json we want to parse some property to the enum constant. Like our custom name for enum serialization and deserialization.

Now let’s consider that we have the same CardType enum class and we want it to encode/decode with our custom name. Everything of the above example remains the same, we just need to change the implementation of CardTypeSerializer class.

object CardTypeSerializer : CommonEnumSerializer<CardType>(serialName = "CardType", choices = CardType.values(), choicesNames = arrayOf("My Silver Card", "Gold Card", "Platinum"))

The CommonEnumSerializer takes the T type class as for generic and in the constructor, it takes three-parameter. Let’s see the detail look on the constructor parameter.

serialName: The serialName for overriding serializer name with our custom name. choices: As a second parameter, you need to pass an Array of enums which you want to encode and decode using kotlinx serialization. In our case, we’re passing all of the CardType enums because we want all of our enums to be serialized. If you want to see the documentation of enum.values method check out this link. choicesNames: As a third parameter, we are passing the custom names for our CardType enums. Now the SILVER card uses the name My Silver Card , the GOLD card will be used Gold Card name and last PLATINUM use the Platinum name for encoding/decode.

fun main() { val silverCardSerializedString = Json.stringify(CardTypeSerializer, CardType.SILVER) val silverCard = Json.parse(CardTypeSerializer, silverCardSerializedString) val platinumCardSerializedString = Json.stringify(CardTypeSerializer, CardType.PLATINUM) val platinumCard = Json.parse(CardTypeSerializer ,platinumCardSerializedString) println(silverCardSerializedString) println(silverCard) println(platinumCardSerializedString) println(platinumCard) } // Output of the above program "My Silver Card" SILVER "Platinum" PLATINUM

You see now it showing our own enum serialization names instead of default enum names.

The above example of custom naming convention for enum serialization and deserialization works fine but it’s hackiness makes me go “ICK!”. Currently, we’ve three enums and we’re passing names for every enum and maybe later we need to have four enums then we need to change our CardTypeSerialzer and add a new custom name for newly added enum.

To make the above example works in a conical way we need to have something like, if we add or modify the enum class then we don’t need to change our serializer.

Serialization & Deserialization of Enum class for parameterize constructor with CommonEnumSerializer

Let’s start this method of enum encoding/decoding by updating the CardType enum class.

@Serializable(with = CardTypeSerializer::class) enum class CardType(override val serialName: String? = null) : SerialEnum { // 1 SILVER("My Silver Card"), // 2 GOLD("Gold Card"), PLATINUM }

Below is the explanation of the above code:

The SerialEnum is an interface with only serialName abstract value in it. As we know an enum class can implement an interface so we override the serialName value as a constructor parameter. Passing the custom serialName for every CardType enum instance otherwise keep it as default which is null. Since every CardType has its own serialName which will be used for custom-named encoding/decoding of enum instance.

Next, here is the implementation of SerialEnum interface.

interface SerialEnum { val serialName: String? }

Before showing you the updated CardTypeSerializer class I want you to add the following extension function for Array class.

fun <T> Array<T>.serial() where T : SerialEnum, T : Enum<T> = this.map { it.serialName ?: it.name }.toTypedArray()

The above serial extension function for Array class accepts the T type class enum which only implements the SerialEnum interface. Inside the serial method, we apply map transformation to every enum and return the serialName if it is not null else we return the name of the enum.

Next, let’s see the updated CardTypeSerializer class.

object CardTypetSerializer : CommonEnumSerializer<CardType>( "CardType", CardType.values(), CardType.values().serial() )

Finally, here the example code of generic enum serialization and deserialization with the parameterized constructor:

fun main() { val silverCardSerializerString = Json.stringify(CardTypeSerializer, CardType.SILVER) val silverCard = Json.parse(CardTypeSerializer, silverCardSerializerString) val platinumCardSerializerString = Json.stringify(CardTypeSerializer, CardType.PLATINUM) val platinumCard = Json.parse(CardTypeSerializer, platinumCardSerializerString) println(silverCardSerializerString) println(silverCard) println(platinumCardSerializerString) println(platinumCard) } // Output of the above code. "My Silver Card" SILVER "PLATINUM" PLATINUM

As you can see in the output section that the silver card using the parameterized name for serialization and deserialization while on the other-hand platinum card just showing its own name because we didn’t pass any parameter for it in CardType enum class.

You can find the complete discussion of “SerialName for Enums” when working with Kotlinx Serialization library here on this link.

That’s it for now. This is my knowledge on how we can serialize and deserialize our enums class when working with Kotlinx Serialization library. If you’ve any suggestions to modify the above method please let me know in the comments section.

Thank you for being here and keep reading 🙂 …

What’s Next