Kotlin Functions

 

Kotlin Serialization: Effortless JSON Handling in Your Android Apps

JSON (JavaScript Object Notation) is a popular data interchange format used in modern web and mobile applications. When working with Android apps, handling JSON data is a common requirement for tasks like retrieving data from APIs or persisting data locally. Traditionally, developers have used various libraries or manual parsing techniques to handle JSON data in Android apps. However, with the introduction of Kotlin Serialization, a new and more effortless solution has emerged.

Kotlin Serialization: Effortless JSON Handling in Your Android Apps

Kotlin Serialization is an official library from JetBrains that provides a seamless way to convert Kotlin objects into JSON format and vice versa. It eliminates the need for boilerplate code and offers a more straightforward approach to serialize and deserialize JSON data. In this blog post, we’ll explore the benefits of using Kotlin Serialization for JSON handling in your Android apps and learn how to integrate it into your projects.

1. Setting Up Kotlin Serialization

Before we start using Kotlin Serialization in our Android project, we need to set up the library. Kotlin Serialization is available through the Kotlin standard library, so you don’t need to add any additional dependencies to your project. However, ensure that you are using Kotlin version 1.4 or later, as this is when Kotlin Serialization was introduced.

2. Annotating Kotlin Classes for Serialization

To enable serialization and deserialization of Kotlin objects, we need to annotate our classes with Kotlin Serialization annotations. Here are some essential annotations and their use cases:

2.1 @Serializable Annotation

The @Serializable annotation marks a class as serializable. This annotation is necessary for Kotlin Serialization to recognize the class for JSON handling. Let’s see an example:

kotlin
import kotlinx.serialization.Serializable

@Serializable
data class User(val name: String, val age: Int)

2.2 Customizing Field Names

You can customize the JSON field names to be different from the Kotlin class property names using the @SerialName annotation:

kotlin
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class User(@SerialName("full_name") val name: String, @SerialName("user_age") val age: Int)

In the example above, the JSON field names will be full_name and user_age, respectively, while the Kotlin class properties are name and age.

2.3 Handling Default Values

Sometimes, JSON data might not have all the fields required by your Kotlin class. Kotlin Serialization handles this situation by providing default values for missing fields using the @SerializaDefaultValue annotation:

kotlin
import kotlinx.serialization.Serializable

@Serializable
data class User(val name: String, val age: Int = 18)

If the JSON data doesn’t include the age field, Kotlin Serialization will automatically set the age property to its default value, which is 18 in this case.

2.4 Ignoring Properties

If you have properties that should be excluded from JSON serialization or deserialization, you can use the @Transient annotation:

kotlin
import kotlinx.serialization.Serializable

@Serializable
data class User(val name: String, @Transient val internalId: String)

In the example above, the internalId property will be ignored during serialization and deserialization.

2.5 Polymorphic Serialization

Kotlin Serialization also supports polymorphic serialization, where a base class can be serialized and deserialized as its derived classes:

kotlin
import kotlinx.serialization.Polymorphic
import kotlinx.serialization.Serializable

@Serializable
sealed class Animal

@Serializable
data class Dog(val breed: String) : Animal()

@Serializable
data class Cat(val color: String) : Animal()

@Serializable
data class Zoo(val animals: List<@Polymorphic Animal>)

In this example, we have a Zoo class containing a list of Animal objects. The @Polymorphic annotation allows Kotlin Serialization to determine the actual type of the objects during serialization and deserialization.

3. Basic Serialization and Deserialization

Once we have annotated our Kotlin classes, Kotlin Serialization can seamlessly handle the conversion between Kotlin objects and JSON strings. Let’s see some examples of basic serialization and deserialization:

kotlin
import kotlinx.serialization.encodeToString
import kotlinx.serialization.decodeFromString

fun main() {
    // Serialization
    val user = User("John Doe", 30)
    val json = Json.encodeToString(user)
    println(json) // Output: {"name":"John Doe","age":30}

    // Deserialization
    val jsonString = """{"name":"Jane Smith","age":25}"""
    val newUser = Json.decodeFromString<User>(jsonString)
    println(newUser) // Output: User(name=Jane Smith, age=25)
}

4. JSON Encoding Formats

Kotlin Serialization supports multiple JSON encoding formats, including JSON (JavaScript Object Notation) and ProtoBuf (Protocol Buffers). Let’s briefly compare these two formats:

4.1 JSON

JSON is a human-readable and lightweight data interchange format. It is widely used for data transmission between server and client applications. Kotlin Serialization provides built-in support for JSON encoding and decoding, making it the default encoding format.

4.2 ProtoBuf

ProtoBuf, short for Protocol Buffers, is a binary serialization format developed by Google. It offers excellent performance and efficiency compared to JSON. Kotlin Serialization allows you to work with ProtoBuf by adding an additional dependency:

kotlin
// build.gradle
implementation "org.jetbrains.kotlinx:kotlinx-serialization-protobuf:1.2.1"

Once the dependency is added, you can use the ProtoBuf format in place of Json:

kotlin
import kotlinx.serialization.protobuf.ProtoBuf

// Serialization
val user = User("John Doe", 30)
val bytes = ProtoBuf.encodeToByteArray(user)

// Deserialization
val newUser = ProtoBuf.decodeFromByteArray<User>(bytes)

Keep in mind that ProtoBuf may not be human-readable, making it more suitable for scenarios where performance is critical.

5. Handling Complex Objects

In real-world applications, JSON data can be more complex than simple key-value pairs. Kotlin Serialization handles complex objects with ease. Let’s explore how to handle various scenarios:

5.1 Nested Objects

When your class contains other serializable classes, Kotlin Serialization can automatically serialize and deserialize nested objects:

kotlin
import kotlinx.serialization.Serializable

@Serializable
data class Address(val street: String, val city: String)

@Serializable
data class User(val name: String, val age: Int, val address: Address)

5.2 Lists and Arrays

Handling lists and arrays is straightforward with Kotlin Serialization:

kotlin
import kotlinx.serialization.Serializable

@Serializable
data class User(val name: String, val age: Int, val hobbies: List<String>)

5.3 Maps

For maps, Kotlin Serialization allows you to use a variety of keys and values:

kotlin
import kotlinx.serialization.Serializable

@Serializable
data class UserProfile(val name: String, val attributes: Map<String, String>)

5.4 Enums

Enums can also be easily serialized and deserialized:

kotlin
import kotlinx.serialization.Serializable

@Serializable
enum class UserRole { ADMIN, USER }

@Serializable
data class User(val name: String, val role: UserRole)

5.5 Nullable Fields

If your JSON data has nullable fields, Kotlin Serialization will handle them gracefully:

kotlin
import kotlinx.serialization.Serializable

@Serializable
data class User(val name: String, val age: Int?)

6. Integration with Retrofit

Retrofit is a popular HTTP client library for Android, and integrating Kotlin Serialization with Retrofit is a breeze. You need to add the Kotlin Serialization converter to your Retrofit instance:

kotlin
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"

Then, build your Retrofit instance with the converter:

kotlin
import retrofit2.Retrofit
import retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json

val retrofit = Retrofit.Builder()
    .baseUrl(BASE_URL)
    .addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
    .build()

Now your Retrofit API can use Kotlin classes for request and response data, and Retrofit will automatically handle serialization and deserialization.

7. Handling Custom Serializers

In some cases, you might need to customize how Kotlin Serialization handles specific data types. Kotlin Serialization allows you to define custom serializers for these scenarios:

kotlin
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*

@Serializer(forClass = LocalDate::class)
object LocalDateSerializer : KSerializer<LocalDate> {
    override val descriptor: SerialDescriptor =
        PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.STRING)

    override fun serialize(encoder: Encoder, value: LocalDate) {
        encoder.encodeString(value.toString())
    }

    override fun deserialize(decoder: Decoder): LocalDate {
        return LocalDate.parse(decoder.decodeString())
    }
}


In this example, we define a custom serializer for the LocalDate class, which is part of the java.time package in Java/Kotlin.

8. Migrating from Other Libraries

If you’ve previously used other JSON libraries like Gson or Moshi, Kotlin Serialization offers a migration guide to help you switch smoothly:

kotlin
val gson = Gson()

// Convert Gson to Kotlin Serialization
val userGson = gson.fromJson(jsonString, User::class.java)
val json = Json.encodeToString(userGson)

9. Performance and Efficiency

Kotlin Serialization is designed to be efficient and performant. It outperforms many other serialization libraries due to its inline code generation and minimal overhead. Additionally, by using ProtoBuf format, you can achieve even better performance in certain scenarios.

Conclusion

In conclusion, Kotlin Serialization brings a powerful and effortless solution for JSON handling in your Android apps. With its intuitive annotations and seamless integration with Retrofit, it simplifies the serialization and deserialization process. Whether you are dealing with simple objects or complex data structures, Kotlin Serialization is a fantastic choice for JSON handling in your Android projects. So, why not give it a try and experience the joy of effortless JSON handling in your app development journey!

Previously at
Flag Argentina
Brazil
time icon
GMT-3
Experienced Android Engineer specializing in Kotlin with over 5 years of hands-on expertise. Proven record of delivering impactful solutions and driving app innovation.