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@Serializabledata 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.Jsonfun 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.*@Serializabledata 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.
To set up Kotlinx Serialization and use the @Serializable annotation, follow these steps:
Step 1: Add Kotlinx Serialization Dependency
First, you need to add the Kotlinx Serialization dependency to your project. In your build.gradle.kts (Kotlin DSL) file, include the following:
plugins { kotlin("plugin.serialization") version "<kotlin_version>"}dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:<version>")}
Replace <kotlin_version> with the version of Kotlin you are using and <version> with the latest version of Kotlinx Serialization (e.g., 1.6.0).
Step 2: Enable Serialization Plugin
In the plugins block, ensure that you have the serialization plugin enabled. This is necessary to process the @Serializable annotations and generate the necessary serialization/deserialization code.
plugins { kotlin("plugin.serialization") version "<kotlin_version>"}
Step 3: Annotate Data Classes with @Serializable
You can now use the @Serializable annotation in your Kotlin code. For example:
import kotlinx.serialization.Serializable@Serializabledata class User(val name: String, val age: Int)
Step 4: Use Serialization and Deserialization Functions
With your class annotated, you can easily serialize and deserialize objects using the Json.encodeToString() and Json.decodeFromString() methods. Here’s an example:
import kotlinx.serialization.json.Jsonfun main() { val user = User("Alice", 30) // Serialize to JSON val jsonString = Json.encodeToString(User.serializer(), user) println(jsonString) // Deserialize from JSON val deserializedUser = Json.decodeFromString(User.serializer(), jsonString) println(deserializedUser)}
Step 5: Run Your Code
Once everything is set up, you can run your Kotlin program, and it will handle JSON serialization and deserialization seamlessly.
Key Takeaways:
Add dependencies in build.gradle.kts.
Enable the kotlinx-serialization plugin.
Annotate your data classes with @Serializable.
Use the Json object for serialization and deserialization.