1. Introduction
Applications often share data using different formats and protocols. This brings up the need to understand how we can convert data from one format to another for every application to carry out its role conveniently.
This tutorial will teach us how to serialize Kotlin data classes containing default values into a JSON format. We can deserialize the JSON obtained back into the original data class without omitting parameters with default values.
2. What Is Data Serialization and Deserialization in Kotlin
Firstly, let’s get some context and meaning of the word serialize.
Data serialization in Kotlin refers to converting data from one format to another. Usually, an application uses data that is originally in a particular format but needs to transfer this data over a network, store it in a database or file, or share it with another external application altogether. To achieve this, the data has to be converted into a convenient format for its destination receiver.
In turn, deserialization is the opposite process. It involves reading data from an external source or over a network and converting it into a runtime object within our application.
In a typical application, serialization and deserialization are often used. For instance, in a client-server system, the backend service sends data in JSON format over to the client application. The client application then deserializes this data into runtime objects that can be used readily. If the client needs to send data over to the backend, it serializes its data into JSON – a format the backend understands.
Kotlin provides the kotlinx-serialization library for data serialization. This library contains the API to parse JSON into type-safe Kotlin objects and vice versa.
3. How to Serialize Data
What’s more important is that we have our kotlinx-serialization library already set up in our project.
Now, let’s try to serialize a Kotlin data class.
We want to serialize the class Car into JSON;
import kotlinx.serialization.Serializable
@Serializable
data class Car(val type: String, val color: String)
The @Serializable annotation on the Car class indicates that it serializes data. Without it, we’ll run into a compilation error.
Next, we use the encodeToString() method from the library to serialize the Car class into JSON format;
val car = Car("Ford", "Grey")
val jsonString = Json.encodeToString(car)
assertEquals("{\"type\":\"Ford\",\"color\":\"Grey\"}" , jsonString)
In contrast, we can deserialize this JSON string back into the Car class object using the decodeFromString() method from the library;
val jsonString = "{\"type\":\"Ford\",\"color\":\"Grey\"}"
val car = Json.decodeFromString<Car>(jsonString)
assertEquals("Ford", car.type)
assertEquals("Grey", car.color)
4. Dealing With Data Class Default Values During Serialization Into JSON
Interestingly, the kotlinx-serialization library’s default behavior does not encode properties with default values. This means that serializing a data class with default value parameters will produce a JSON string that omits such parameters. This is so because, in most real-world scenarios, such a configuration helps to reduce the amount of data being serialized.
Let’s give our Car class a default value for the color property;
import kotlinx.serialization.Serializable
@Serializable
data class Car(val type: String, val color: String = "Blue")
Now, we serialize the Car class;
val car = Car("Ford")
val jsonString = Json.encodeToString(car)
assertEquals("{\"type\":\"Ford\"}", jsonString)
We notice that the color property is missing from the JSON string, and that’s because color has a default value.
Nevertheless, it’s not uncommon to desire the encoding of properties with default values in our applications. We’ll see two ways to achieve that.
The first method entails that we describe a format setting for JSON and set the encodeDefaults to true. We then call the encodeToString() method from that format setting;
val format = Json { encodeDefaults = true }
val car = Car("Ford")
val jsonString = format.encodeToString(car)
assertEquals("{\"type\":\"Ford\",\"color\":\"Blue\"}", jsonString)
So, although the color property has a default value, by defining a configuration setting for JSON, we can have it encoded as well.
The second method we can use doesn’t require defining a configuration setting as in the first method. Instead, we use the @EncodeDefault annotation directly on the property having a default value. This annotation instructs the framework to serialize the said property regardless of its value or configuration setting.
So, let’s modify our Car class;
import kotlinx.serialization.Serializable
@Serializable
data class Car(val type: String, @EncodeDefault val color: String = "Blue")
We can then serialize this class normally into JSON;
val car = Car("Ford")
val jsonString = Json.encodeToString(car)
assertEquals("{\"type\":\"Ford\",\"color\":\"Blue\"}", jsonString)
5. Conclusion
There are many use cases for serializing data. Firstly, it allows us to share data with other platforms and environments, enabling us to access our data from anywhere. Finally, serialization permits us to read and comprehend other data formats.
In this tutorial, we’ve learned what data serialization is, how we can serialize a data class in Kotlin, and how we can deal with default value properties during serialization.
Code samples and relevant test cases can be found over on GitHub.