1. Introduction

While working on various applications, dealing with data in different formats is often needed. For such applications to execute as intended, they rely on data from other applications or platforms, usually in a format that makes them not immediately usable in our applications. Therefore, we need to convert this data into another format so that our application can proceed with its intended execution.

2. What Is Data Serialization and Deserialization

Before we get into the subject matter of this tutorial, it is pertinent that we, first of all, get clarification of terms such as Serialization and Deserialization.

Serialization in Kotlin refers to converting data from one format to another. Usually to format that is compatible with the applications we are working on. For example, receiving data from a back-end service in JSON format and converting this data into Data class objects that could be used readily.

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 Kotlin, we mostly carry out serialization by converting our Data classes into JSON objects. While deserialization involves converting JSON objects into Data class objects.

This tutorial will take it further by addressing the Serialization of Arrays in Kotlin.

3. How to Perform Serialization and Deserialization in Kotlin

Firstly, let’s discuss briefly how we can serialize and deserialize objects in Kotlin using Kotlin’s out-of-the-box kotlinx-serialization library.

To serialize the data class Person into JSON, we need to include the @Serializable annotation in the class:

import kotlinx.serialization.Serializable

@Serializable
data class Person(val gender: String, val name: String)

Now, we use the encodeToString() method to convert this class to JSON format:

val p = Person("male", "Ethan")
val jsonString = Json.encodeToString(p)
assertEquals("{\"gender\":\"Male\",\"name\":\"Ethan\"}" , jsonString)

Alternatively, we can deserialize the jsonString from above back into a data class object using the decodeFromString():

val jsonString = "{\"gender\":\"male\",\"name\":\"Ethan\"}"
val p = Json.decodeFromString<Person>(jsonString)
assertEquals("male", p.gender)
assertEquals("Ethan", p.name)

4. How to Serialize Arrays in Kotlin

The previous section demonstrates how to serialize and deserialize data in Kotlin. However, on many occasions, while working on some applications, we tend to have scenarios where the data from the back-end or third-party service requires that we serialize into some sort of list or Array.

For instance, imagine a scenario where we need to load all the posts made by a user in our applications. This usually requires that the back-end service delivers the JSON list representing the posts made by a user. This JSON list needs to be further serialized into an array within our applications to be used properly.

Let’s try to demonstrate this concept with some code.

Firstly, we define a Post data class that holds all properties for a Post:

@Serializable
data class Post(val author: String, val title: String, val id: String)

We can then create a list of Posts and serialize them normally:

val p1 = Post("Ethan", "Title 1", "1")
val p2 = Post("Joel", "Title 2", "2")
val p3 = Post("Jay", "Title 3", "3")
val p4 = Post("Mat", "Title 4", "4")

val posts = arrayOf(p1, p2, p3, p4)
val jsonString = Json.encodeToString(posts)
val res = "[{\"author\":\"Ethan\",\"title\":\"Title 1\",\"id\":\"1\"}," +
  "{\"author\":\"Joel\",\"title\":\"Title 2\",\"id\":\"2\"}," +
  "{\"author\":\"Jay\",\"title\":\"Title 3\",\"id\":\"3\"}," +
  "{\"author\":\"Mat\",\"title\":\"Title 4\",\"id\":\"4\"}]"
assertEquals(res, jsonString)

Contrarily, we could use the JSON list of posts to obtain a list of Post objects:

val res = "[{\"author\":\"Ethan\",\"title\":\"Title 1\",\"id\":\"1\"}," +
  "{\"author\":\"Joel\",\"title\":\"Title 2\",\"id\":\"2\"}," +
  "{\"author\":\"Jay\",\"title\":\"Title 3\",\"id\":\"3\"}," +
  "{\"author\":\"Mat\",\"title\":\"Title 4\",\"id\":\"4\"}]"

val posts = Json.decodeFromString<Array<Post>>(res)
assertEquals(4,posts.size)
assertEquals("Ethan", posts[0].author)

Notice that, unlike the normal way to deserialize JSON into a data class object, the decodeFromString() method casts the object to an Array type.

It is also worth mentioning that working on real-world applications sometimes compels us to work with complex data, such as nested JSON objects or data classes that also harbour other data objects as their inherent properties.

Let’s say our Post class now contains some metadata objects. The metadata object contains the location and day the post was made.

We now have new data classes:

@Serializable
data class MetaData(val location: String, val day: String)

@Serializable
data class PostWithMetaData(val author: String, val title: String, val id: String, val metaData: MetaData)

We then proceed to serialize a list of PostWithMetaData:

val m1 = MetaData("NY", "Monday")
val m2 = MetaData("Dubai", "Friday")
val m3 = MetaData("Croatia", "Thursday")
val m4 = MetaData("Douala", "Wednesday")

val p1 = PostWithMetaData("Ethan", "Title 1", "1", m1)
val p2 = PostWithMetaData("Joel", "Title 2", "2", m2)
val p3 = PostWithMetaData("Jay", "Title 3", "3", m3)
val p4 = PostWithMetaData("Mat", "Title 4", "4", m4)

val posts = arrayOf(p1, p2, p3, p4)
val res = "[{\"author\":\"Ethan\",\"title\":\"Title 1\",\"id\":\"1\",\"metaData\":{\"location\":\"NY\",\"day\":\"Monday\"}}," +
  "{\"author\":\"Joel\",\"title\":\"Title 2\",\"id\":\"2\",\"metaData\":{\"location\":\"Dubai\",\"day\":\"Friday\"}}," +
  "{\"author\":\"Jay\",\"title\":\"Title 3\",\"id\":\"3\",\"metaData\":{\"location\":\"Croatia\",\"day\":\"Thursday\"}}," +
  "{\"author\":\"Mat\",\"title\":\"Title 4\",\"id\":\"4\",\"metaData\":{\"location\":\"Douala\",\"day\":\"Wednesday\"}}]"
val jsonString = Json.encodeToString(posts)
assertEquals(res, jsonString)

Using the same res JSON String, we can deserialize it into an array of PostWithMetaData objects:

val res = "[{\"author\":\"Ethan\",\"title\":\"Title 1\",\"id\":\"1\",\"metaData\":{\"location\":\"NY\",\"day\":\"Monday\"}}," +
  "{\"author\":\"Joel\",\"title\":\"Title 2\",\"id\":\"2\",\"metaData\":{\"location\":\"Dubai\",\"day\":\"Friday\"}}," +
  "{\"author\":\"Jay\",\"title\":\"Title 3\",\"id\":\"3\",\"metaData\":{\"location\":\"Croatia\",\"day\":\"Thursday\"}}," +
  "{\"author\":\"Mat\",\"title\":\"Title 4\",\"id\":\"4\",\"metaData\":{\"location\":\"Douala\",\"day\":\"Wednesday\"}}]"
val posts = Json.decodeFromString<Array<PostWithMetaData>>(res)
assertEquals(4,posts.size) assertEquals("Monday", posts[0].metaData.day)
assertEquals("Friday", posts[1].metaData.day)
assertEquals("Thursday", posts[2].metaData.day)
assertEquals("Wednesday", posts[3].metaData.day)

5. Conclusion

This article explains how data can be serialized and deserialized using Kotlin’s own kotlinx-serialization library. It handles complex scenarios like nested JSON or data classes with other object properties.

Code samples and relevant test cases can be found over on GitHub.