- Serialization
- Libraries
- Formats
- Example: JSON serialization
- How to Serialize Your Data in Kotlin and Jetpack Compose
- How to Set Everything Up
- How to Build Your Data Class
- How to Serialize and De-Serialize
- Сериализация Kotlin с помощью Kotlinx.Serialization
- Пример Grundle для мультиплатформенного использования
- Для Android
- Сериализация
- @Transient и @Optional
- Пример для Android с использованием Retrofit
- Список репозиториев
Serialization
Serialization is the process of converting data used by an application to a format that can be transferred over a network or stored in a database or a file. In turn, deserialization is the opposite process of reading data from an external source and converting it into a runtime object. Together they are an essential part of most applications that exchange data with third parties.
Some data serialization formats, such as JSON and protocol buffers are particularly common. Being language-neutral and platform-neutral, they enable data exchange between systems written in any modern language.
In Kotlin, data serialization tools are available in a separate component, kotlinx.serialization. It consists of several parts: the org.jetbrains.kotlin.plugin.serialization Gradle plugin, runtime libraries, and compiler plugins.
Compiler plugins, kotlinx-serialization-compiler-plugin and kotlinx-serialization-compiler-plugin-embeddable , are published directly to Maven Central. The second plugin is designed for working with the kotlin-compiler-embeddable artifact, which is the default option for scripting artifacts. Gradle adds compiler plugins to your projects as compiler arguments.
Libraries
kotlinx.serialization provides sets of libraries for all supported platforms – JVM, JavaScript, Native – and for various serialization formats – JSON, CBOR, protocol buffers, and others. You can find the complete list of supported serialization formats below.
All Kotlin serialization libraries belong to the org.jetbrains.kotlinx: group. Their names start with kotlinx-serialization- and have suffixes that reflect the serialization format. Examples:
- org.jetbrains.kotlinx:kotlinx-serialization-json provides JSON serialization for Kotlin projects.
- org.jetbrains.kotlinx:kotlinx-serialization-cbor provides CBOR serialization.
Platform-specific artifacts are handled automatically; you don’t need to add them manually. Use the same dependencies in JVM, JS, Native, and multiplatform projects.
Note that the kotlinx.serialization libraries use their own versioning structure, which doesn’t match Kotlin’s versioning. Check out the releases on GitHub to find the latest versions.
Formats
kotlinx.serialization includes libraries for various serialization formats:
Note that all libraries except JSON serialization ( kotlinx-serialization-json ) are Experimental, which means their API can be changed without notice.
There are also community-maintained libraries that support more serialization formats, such as YAML or Apache Avro. For detailed information about available serialization formats, see the kotlinx.serialization documentation.
Example: JSON serialization
Let’s take a look at how to serialize Kotlin objects into JSON.
Before starting, you’ll need to configure your build script so that you can use Kotlin serialization tools in your project:
- Apply the Kotlin serialization Gradle plugin org.jetbrains.kotlin.plugin.serialization (or kotlin(«plugin.serialization») in the Kotlin Gradle DSL).
How to Serialize Your Data in Kotlin and Jetpack Compose
Serialization is the process of transforming data that’s in one format into another format that can be stored.
If you have ever worked with a database or fetching data from a server, this should all be familiar to you. If not, you have come to the right place.
In this tutorial, we will go over:
- How to setup serialization in a Jetpack Compose project
- How to serialize a data class
- How to de-serialize a data class
You might be asking yourself, what’s so special about serialization in Jetpack Compose? In essence, there isn’t a lot of difference than with a regular Kotlin Android project. The only difference is in the setup.
How to Set Everything Up
Each version of Jetpack Compose corresponds with a version of Kotiln that it is compatible with. Each version of the kotlin-serialization library is also compatible with a specific version of Kotlin. So you need to make sure that each of the three parts in this tripod are compatible with one another.
Your first resource you’ll want to consult is the Compose to Kotlin Compatibility Map.
Here you can see which version of Jetpack Compose corresponds to which Kotlin version.
The second resource you will need is the releases page for the kotlin-serialization library. There you will find which library version is compatible with which Kotlin version.
Let’s illustrate this with an example:
- Your Jetpack Compose version is 1.1.0.
- Looking over the compatibility map, you see it is compatible with Kotlin version 1.6.10.
- Heading to the releases page of kotlin-serialization library, you see that the version of the kotlin-serialization library that you need to use is 1.3.2.
Head into your project level build.gradle file, and inside the buildscript object, in the dependencies section, put in classpath for the kotlin-serialization library with the version you need.
Then, head over to your application build.gradle file and do these two things:
- Add the id ‘org.jetbrains.kotlin.plugin.serialization’ inside of the plugins at the top of the file:
2. At the bottom of the file, inside the dependencies section add implementation ‘org.jetbrains.kotlinx:kotlinx-serialization-json:X.Y.Z’:
Sync your project and you should be good to go.
Note that we are using the json format of the library, but there are other formats that are supported as well:
- Protocol Buffers
- CBOR (Concise Binary Object Representation)
- Properties
- HOCON (Human Optimized Config Object Notation)
How to Build Your Data Class
In order to have something we can serialize and later de-serialize, we need to work with data classes.
Creating a data class is simple. If you are using Android Studio, just right click inside your project’s module and choose New Kotlin file. Enter your class name and then append the data keyword before it.
For the sake of this article, let’s say we are working with an API that returns a list of users. Each user object has a range of attributes it can have (just to name a few):
To make our data class serializable, all you need to do is add the @Serializable annotation above the class declaration.
@Serializable data class UserModel( val firstName: String, val lastName: String, val age: Int, val birthdate: Date, val id: Long )
The variable that will hold the user’s first name is written as firstName. That means that in the response from our server, it needs to return in a field with the same name.
Sometimes, in API responses, the keys are not written in camelCase, but rather in kebab_case. That would mean that the key for first name, might be first_name. In that case, we would have to write it out like this:
@Serializable data class UserModel( val first_name: String, val lastName: String, val age: Int, val birthdate: Date, val id: Long )
But that is not the convention for property names in Kotlin.
We can use the @SerialName annotation. This allows us to mark what the name of the field will be from the response and then write anything as the property for it.
@Serializable data class UserModel( @SerialName("first_name") val firstName: String, val lastName: String, val age: Int, val birthdate: Date, val id: Long )
How to Serialize and De-Serialize
Now that our data class is set up, let’s enjoy the fruits of our labor. Whenever we need to serialize our data class, we will use the Json.encodeToString method:
val dataAsString: String = Json.encodeToString(user)
When we run the above line of code, we will get our data class in string form.
De-serializing our data is as simple as serializing it. We will use the Json.decodeFromString method:
val user: UserModel = Json.decodeFromString(dataAsString)
Time for some extra credit.
Let’s say that in your data class you have a field that you don’t want to serialize. If we take our UserModel class, imagine that we want to have a user’s actual picture (bitmap).
@Serializable data class UserModel( @SerialName("first-name") val firstName: String, val lastName: String, val age: Int, val birthdate: Date, val id: Long, var photo: Bitmap? )
This is not something we will get from our API call, so how can we exclude it? Because if we don’t, our serialization will fail.
@Serializable data class UserModel( @SerialName("first-name") val firstName: String, val lastName: String, val age: Int, val birthdate: Date, val id: Long, @Transient var photo: Bitmap? )
This will exclude the marked field from being serialized and de-serialized.
- If you want to see a real life example of using serialization inside a project, you can check out a project I made here
- And if you would like to read other articles I have written, you can go here
- For more information about the kotlin-serialization library, you can go here
Thank you for reading! Happy serializing.
Сериализация Kotlin с помощью Kotlinx.Serialization
После работы над мультиплатформенной библиотекой, которая собирала .framework и .aar артефакты, я пришел к выводу, что есть большое количество полезных вещей, уже есть в Kotlin, но многие из нас никогда о них не знали.
Одна из вещей, о которой вы обязательно должны позаботиться при создании мультиплатформенного проекта — это библиотеки, которые вы используете при разработке. Лучше всего стоит придерживаться решений, предоставленных Kotlin «из коробки».
Так, когда я попал в ситуацию, когда появилась необходимость сериализовать JSON документ, который нужно было использовать на двух платформах(iOS и Android), появились проблемы в компиляции проекта под iOS. После небольших поисков, я нашёл Kotlinx Serializtion library.
Если быть откровенным, я никогда не знал об этой библиотеки, так что эта публикация в большей степени для людей, которые так же как и я не знали об этом инструменте.
Процесс настройки проекта для использования плагина достаточно хорошо описан в репозитории на Гитхабе. Но я буду настраивать проект как для Android, так и для мультиплатформенного использования.
Единственное, что надо сделать при мультиплатформенной компиляции, нужно добавить зависимости в конец зависитмостей в вашем нативном grandle файле.
implementation org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:0.9.1
Пример Grundle для мультиплатформенного использования
plugins < id 'kotlin-multiplatform' version '1.3.11' id 'kotlinx-serialization' version '1.3.10' >repositories < google() jcenter() mavenCentral() maven < url "https://kotlin.bintray.com/kotlinx" >> apply plugin: 'com.android.library' apply plugin: 'kotlin-android-extensions' android < compileSdkVersion 28 defaultConfig < minSdkVersion 15 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" >buildTypes < release < minifyEnabled false >> > dependencies < implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' androidTestImplementation 'com.android.support.test:runner:1.0.2' >kotlin < targets < fromPreset(presets.android, 'android') // Пресет для эмулятора iPhone // Поменяйте гп presets.iosArm64 (или iosArm32) чтобы собрать библиотеку для iPhone fromPreset(presets.iosX64, 'ios') < compilations.main.outputKinds('FRAMEWORK') >> sourceSets < commonMain < dependencies < implementation 'org.jetbrains.kotlin:kotlin-stdlib-common' implementation 'org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.9.1' >> commonTest < dependencies < implementation 'org.jetbrains.kotlin:kotlin-test-common' implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common' >> androidMain < dependencies < implementation 'org.jetbrains.kotlin:kotlin-stdlib' >> androidTest < dependencies < >> iosMain < dependencies< implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:0.9.1" >> iosTest < >> >
Для Android
apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlinx-serialization' android < compileSdkVersion 28 defaultConfig < applicationId "com.example.smile.kotlinxretrosample" minSdkVersion 16 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" >buildTypes < release < minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' >> > dependencies
Сериализация
Чтобы сериализировать класс, просто добавьте перед ним аннотацию @Serializable
import kotlinx.serialization.Serializable @Serializable class Field
Серилиазация работает и с классами данных
Теперь, попробуем написать небольшой пример для преобразования JSON в объект и обратно.
/* * < length = 20 hint = "example" required= false >*/ fun toObject(stringValue: String): Field < return JSON.parse(Field.serializer(), stringValue) >fun toJson(field: Field): String < // Обратите внимание, что мы вызываем Serializer, который автоматически сгенерирован из нашего класса // Сразу после того, как мы добавили аннотацию @Serializer return JSON.stringify(Field.serializer(), field) >
@Transient и @Optional
Еще две аннотации о который стоит рассказать это:
- @Transient — Покажет Serializer’y что поле нужно проигнорировать.
- @Optional — Serializer не остановиться и не выкинет ошибку, если поле отсутствует, но в тоже самое время значение по-умолчанию все равно должно быть установлено.
@Optional var isOptional: Boolean = false @Transient var isTransient: Boolean = false
Пример для Android с использованием Retrofit
Для тех, кто хочет использовать этот плагин в разработке для Андроида, Retrofit 2 имеет адаптер. Ссылка на адаптер.
un createRetrofit(): Retrofit < val contentType = MediaType.get("application/json") return Retrofit.Builder() .addConverterFactory(serializationConverterFactory(contentType, JSON)) .baseUrl(BASE_URL) .client(provideOkhttpClient()) .build() >
Если ваш класс уже имеет аннотации, то после отправки запроса ваш класс должен превратиться в JSON объект.
В общем, сериализация в Kotlin’e является отличным дополнением для любого проекта и делает сам процесс сохранения данных в строчке или JSON объекте гораздо более простым менее трудозатратным.
Список репозиториев
- KotlinxRetrofit — небольшой работащий пример использования сериализации на Android
- kotlinx.serialization — Основной репозиторий библиотеки