kotlinx-serialization-json-@Serializable

Kotlinx Serialization and @Serializable Annotation

Overview

Kotlinx Serialization is a Kotlin library that provides a multiplatform and idiomatic way to serialize and deserialize Kotlin objects. It supports various formats such as JSON, ProtoBuf, CBOR, and more. The library is designed to work seamlessly with Kotlin's data classes and sealed classes, ensuring type safety and ease of use.

@Serializable Annotation

The @Serializable annotation is the cornerstone of Kotlinx Serialization. It marks a class for automatic generation of serialization and deserialization code. By annotating a class with @Serializable, you enable it to be easily converted to and from JSON (or other formats supported by the library).

Usage

Annotating Data Classes

To use @Serializable, simply annotate your Kotlin data class:

import kotlinx.serialization.Serializable

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

Serialization and Deserialization

Once a class is annotated, you can use the provided serialization and deserialization functions:

import kotlinx.serialization.json.Json

fun main() {
    val user = User("Alice", 30)
    
    // Serialize to JSON
    val jsonString = Json.encodeToString(User.serializer(), user)
    println(jsonString) // Output: {"name":"Alice","age":30}

    // Deserialize from JSON
    val deserializedUser = Json.decodeFromString(User.serializer(), jsonString)
    println(deserializedUser) // Output: User(name=Alice, age=30)
}

Custom Serialization

You can also define custom serialization logic by implementing the KSerializer interface or using the @Serializable with custom serializers:

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

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

object UserSerializer : KSerializer<User> {
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("User") {
        element<String>("name")
        element<Int>("age")
    }

    override fun serialize(encoder: Encoder, value: User) {
        val composite = encoder.beginStructure(descriptor)
        composite.encodeStringElement(descriptor, 0, value.name)
        composite.encodeIntElement(descriptor, 1, value.age)
        composite.endStructure(descriptor)
    }

    override fun deserialize(decoder: Decoder): User {
        val dec = decoder.beginStructure(descriptor)
        var name = ""
        var age = 0
        loop@ while (true) {
            when (val index = dec.decodeElementIndex(descriptor)) {
                0 -> name = dec.decodeStringElement(descriptor, 0)
                1 -> age = dec.decodeIntElement(descriptor, 1)
                CompositeDecoder.DECODE_DONE -> break@loop
                else -> throw SerializationException("Unknown index $index")
            }
        }
        dec.endStructure(descriptor)
        return User(name, age)
    }
}

fun main() {
    val user = User("Alice", 30)
    
    // Serialize with custom serializer
    val jsonString = Json.encodeToString(UserSerializer, user)
    println(jsonString) // Output: {"name":"Alice","age":30}

    // Deserialize with custom serializer
    val deserializedUser = Json.decodeFromString(UserSerializer, jsonString)
    println(deserializedUser) // Output: User(name=Alice, age=30)
}

Benefits

  • Multiplatform Support: Works across JVM, JavaScript, and Native platforms.
  • Type Safety: Ensures that your data conforms to the expected types.
  • Integration with Kotlin Features: Works seamlessly with data classes, sealed classes, and other Kotlin features.
  • Extensibility: Allows custom serialization logic for complex use cases.

Conclusion

Kotlinx Serialization, with its @Serializable annotation, provides a powerful and flexible way to handle serialization in a Kotlin-centric manner. It offers multiplatform support, type safety, and ease of use, making it a go-to choice for Kotlin developers looking to serialize and deserialize their data effectively.