kotlinx.serialization: bu nədir, annotasiyalar və JSON serializasiyası

Müəllif: IT Sectr Dərc olunub: 2026-03-15 Oxuma vaxtı: 12 dəq

kotlinx.serialization — JetBrains tərəfindən Kotlin obyektlərini JSON, ProtoBuf, CBOR və digər formatlara çevirmək üçün refleksiyasız çoxplatformalı kitabxana. Gson və Moshidən fərqli olaraq, @Serializable annotasiyası vasitəsilə kompilasiya mərhələsində serializator kodu yaradır ki, bu da yüksək performans və tip təhlükəsizliyi təmin edir. GitHub Kotlin/kotlinx.serialization məlumatlarına görə, kitabxana Kotlin/JVM, Kotlin/Native, Kotlin/JS və Kotlin/Wasm dəstəkləyir.

Başlıca

  • kotlinx.serialization — kompilasiya zamanı serializasiya: kod kompilasiya mərhələsində yaradılır, refleksiya istifadə edilmir
  • @Serializable — sinif üçün serializator yaradılmasını başladan əsas annotasiya
  • Json {} builder — JSON konfiqurasiyası: Json { ignoreUnknownKeys = true; prettyPrint = true }
  • Çoxplatformalılıq — kitabxana API dəyişmədən JVM, Native, JS və Wasm üzərində işləyir
  • Xüsusi serializatorlar — qeyri-standart məlumat formatları üçün KSerializer interfeysi vasitəsilə

kotlinx.serialization nədir

kotlinx.serialization — JetBrains tərəfindən rəsmi Kotlin ekosisteminin bir hissəsi kimi hazırlanmış Kotlin üçün daxili serializasiya kitabxanasıdır. Onun üçüncü tərəf həllərdən (Gson, Moshi, Jackson) əsas fərqi icra zamanı refleksiyadan istifadə etməməsidir. Bunun əvəzinə serializator kodu Kotlin Symbol Processing (KSP) və ya Kotlin Compiler Plugin vasitəsilə kompilasiya mərhələsində yaradılır. Bu, Gson ilə müqayisədə 3-5 dəfəyə qədər performans artımı və tip təhlükəsizliyi təmin edir.

Kitabxana rəsmi olaraq dörd formatı dəstəkləyir: JSON (kotlinx-serialization-json modulu vasitəsilə), ProtoBuf (kotlinx-serialization-protobuf), CBOR (kotlinx-serialization-cbor) və HOCON (kotlinx-serialization-hocon). Formatlar build.gradle.kts faylında ayrı asılılıqlar kimi əlavə edilir ki, bu da layihəyə lazımsız kitabxanaları əlavə etməməyə imkan verir. Hər format üçün öz konfiqurasiya parametrləri dəsti mövcuddur.

Çoxplatformalılıq — kitabxananın əsas xüsusiyyəti. @Serializable ilə eyni sinif bütün hədəf platformalarda işləyir: JVM (Android, Backend), Native (iOS), JS (Web, React) və Wasm (WebAssembly). Tərtibatçı hər platforma üçün fərqli serializasiya tətbiqləri yazmalı deyil — kod vahid qalır. Bu, xüsusilə ümumi kodun Android və iOS arasında bölüşdüyü Kotlin Multiplatform Mobile (KMM) layihələrində dəyərlidir.

Kompilasiya zamanı kod yaradılması necə işləyir

Kod yaradılması kotlinx.serialization-da üç mərhələdə baş verir. Birinci mərhələdə Kotlin kompilatoru sinifdə @Serializable annotasiyasını aşkar edir və onu Kotlin Symbol Processing (KSP) plagininə ötürür. İkinci mərhələdə KSP KSerializer interfeysini tətbiq edən serializator obyekti yaradır. Üçüncü mərhələdə yaradılan kod layihənin mənbə kodu ilə birlikdə kompilasiya olunur. Nəticədə, bu mərhələlərdən heç biri tətbiqin işləməsi zamanı yerinə yetirilmir.

Yaradılan serializator sinifin sahələri ilə birbaşa onların getter və setterləri vasitəsilə, refleksiyasız işləyir. Bu o demɗkdir ki, private modifikatoru olan sahələr də @Serializable ilə qeyd olunubsa, serializasiya olunur. Bu yanaşmanın performansı əl ilə serializasiyaya yaxındır: sadə siniflər (5-10 sahə) üçün serializasiya müddəti 10-50 mikrosaniyə, mürəkkəb obyekt qrafları üçün 1000 obyektə 200 mikrosaniyəyə qədərdir.

Android və ya Kotlin/JVM layihəsində kitabxananı qoşmaq üçün build.gradle.kts faylına plagin və asılılıqlar əlavə etmək lazımdır. Kotlin versiyası ilə üst-üstə düşən org.jetbrains.kotlin.plugin.serialization plagini kod yaradılmasını aktivləşdirir. kotlinx-serialization-json kitabxanası dependencies bölməsində Kotlin versiyasından asılı olmayan versiya ilə əlavə edilir.

kotlin
// build.gradle.kts — kotlinx.serialization qoşulması
plugins {
    val kotlinVersion = "2.1.0"
    kotlin("jvm") version kotlinVersion
    kotlin("plugin.serialization") version kotlinVersion
}

dependencies {
    // Əsas serializasiya modulu
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")

    // Əlavə formatlar
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:1.7.3")
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-cbor:1.7.3")
}

Əsas istifadə: JSON serializasiyası

JSON — kotlinx.serialization-da ən məşhur format. Obyekti serializasiya etmək üçün data class üzərində @Serializable annotasiyası yerləşdirmək və Json.encodeToString() çağırmaq kifayətdir. Deserializasiya üçün — Json.decodeFromString() tip göstərilməklə. Kitabxana avtomatik olaraq null sahələri, siyahıları, iç-içə obyektləri və enumları idarə edir. Sinifin bütün sahələri başqa cür göstərilməyibsə, məcburidir.

JSON konfiqurasiyası Json {} builder vasitəsilə həyata keçirilir. Konstruktora deserializasiya zamanı naməlum sahələri ötürmək üçün ignoreUnknownKeys = true, formatlaşdırılmış çıxış üçün prettyPrint = true, səhv qiymətləri defolt qiymətlərə çevirmək üçün coerceInputValues = true ötürülə bilər. Həmçinin encodeDefaults (defolt qiymətləri olan sahələrin serializasiyası) və classDiscriminator (polimorf serializasiya üçün sahə adı) parametrləri mövcuddur.

kotlin
// JSON serializasiyası və deserializasiyası nümunəsi
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration

@Serializable
data class Project(
    val name: String,
    val stars: Int,
    val isActive: Boolean = true,
    val languages: List<String> = emptyList()
)

fun main() {
    val project = Project(
        name = "kotlinx.serialization",
        stars = 7200,
        languages = listOf("Kotlin", "Java")
    )

    // prettyPrint ilə JSON serializasiyası
    val json = Json { prettyPrint = true }
    val jsonString = json.encodeToString(project)
    println(jsonString)
    /*
    {
        "name": "kotlinx.serialization",
        "stars": 7200,
        "isActive": true,
        "languages": ["Kotlin", "Java"]
    }
    */

    // JSON-dan deserializasiya
    val decoded = json.decodeFromString<Project>(jsonString)
    println(decoded.name)  // kotlinx.serialization
}

Nümunə əsas dövranı — serializasiya və deserializasiyanı göstərir. @Serializable annotasiyası olan Project data class avtomatik olaraq encodeToString və decodeFromString əldə edir. isActive sahəsinin defolt qiyməti true-dur — əgər JSON-da bu sahə yoxdursa, defolt dəyər istifadə olunur. Əgər ignoreUnknownKeys = true olmadan JSON-da naməlum sahələr gələrsə, SerializationException istisnası atılacaq.

Sealed class polimorf serializasiyası

Sealed class — kotlinx.serialization üçün ən güclü istifadə hallarından biri. Kitabxana sealed class iyerarxiyaları üçün əlavə konfiqurasiya olmadan polimorf serializasiyanı dəstəkləyir: sealed class və onun bütün varislərini @Serializable ilə qeyd etmək kifayətdir. Serializasiya zamanı „type” sahəsi (classDiscriminator vasitəsilə konfiqurasiya olunur) əlavə edilir ki, deserializasiya zamanı konkret tip müyən edilir.

kotlin
// Sealed class polimorf serializasiyası
@Serializable
sealed class Response

@Serializable
data class Success(val data: String) : Response()

@Serializable
data class Error(val code: Int, val message: String) : Response()

fun main() {
    val json = Json { classDiscriminator = "result_type" }

    val responses: List<Response> = listOf(
        Success(data = "Data loaded"),
        Error(code = 404, message = "Not found")
    )

    val jsonString = json.encodeToString(responses)
    println(jsonString)
    /*
    [
        {"result_type":"Success","data":"Data loaded"},
        {"result_type":"Error","code":404,"message":"Not found"}
    ]
    */

    val decoded = json.decodeFromString<List<Response>>(jsonString)
    when (val first = decoded[0]) {
        is Success -> println("Success: ${first.data}")
        is Error -> println("Error: ${first.code}")
    }
}

Sealed class polimorf serializasiyası xüsusilə API müştərilərində faydalıdır, burada server müxtəlif cavab növləri qaytarır. kotlinx.serialization olmadan diskriminator sahəsinə görə when ilə əl ilə deserializator yazmaq lazım gələrdi. Kitabxana ilə bu bir annotasiya ilə həll edilir. classDiscriminator marker sahəsinin adını (defolt „type”) serverin gözlədiyi istənilən dəyərə dəyişməyə imkan verir.

kotlinx.serialization annotasiyaları: tam icmal

Kitabxana serializasiyanın incə tənzimlənməsi üçün annotasiyalar dəsti təqdim edir. Əsas annotasiya sinif üçün @Serializable-dır. Əlavələr: JSON-da sahə adını təyin etmək üçün @SerialName (Kotlin adından fərqlidirsə), sahəni serializasiyadan çıxarmaq üçün @Transient, JSON-da mütləq olmalı sahə üçün @Required, defolt qiyməti olan sahənin məcburi serializasiyası üçün @EncodeDefault.

AnnotasiyaTəyinatNümunə
@SerializableSinif üçün serializator yaradılmasını aktivləşdirir@Serializable data class User
@SerialNameSahənin formatda alternativ adını təyin edir@SerialName(“user_name”) val name: String
@TransientSahəni serializasiyadan çıxarır@Transient val cache: MutableMap
@RequiredSahə deserializasiya zamanı JSON-da məcburidir@Required val id: String
@EncodeDefaultSahəni hətta defolt qiymətlə belə serializasiya edir@EncodeDefault val type: Type = Type.A
@SerializerSinfə xüsusi serializator əlavə edir@Serializer(forClass = Date::class)

@SerialName annotasiyası sahə adlarının snake_case, Kotlin stilinin isə camelCase olduğu API-lərdə işləyərkən kritikdir. Məsələn, server “user_id” göndərir, Kotlin kodunda isə userId istifadə olunur. @SerialName(“user_id”) bu problemi əlavə mapperlər olmadan həll edir. @Transient serverə göndərilməsi lazım olmayan sahələr üçün əlverişlidir — məsələn, müvəqqəti hesablama dəyərləri və ya keş.

@Required nullable sahələrə alternativ olaraq

Defolt olaraq kotlinx.serialization-da bütün sahələr məcburidir. Əgər sahə JSON-da olmaya bilərsə, onu nullable (String?) etmək və ya defolt qiymət təyin etmək lazımdır (val name: String = “”). Bununla belə, sahənin Kotlin-də nullable olmadığı, lakin API versiyalaşdırma səbəbindən JSON-da olmaya biləcəyi hallar var. Bu halda @Required sahə yox olduqda SerializationException atır, defolt qiymət isə xətasız default-u doldurur.

Xüsusi serializatorlar: KSerializer və əl ilə idarəetmə

KSerializer — kotlinx.serialization-da bütün serializatorların tətbiq etdiyi interfeys. Standart kod yaradılması uyğun deyilsə (məsələn, Date, Bitmap və ya xüsusi ikilik formatla iş üçün), öz serializatorunuzu yaza bilərsiniz. Bunun üçün serialize() və deserialize() metodlarını, həmçinin format sxemi üçün descriptor təqdim etmək lazımdır.

Xüsusi serializatorlar iki yolla qoşulur: konkret sinfə bağlamaq üçün @Serializable(with = MySerializer::class) annotasiyası və ya Json { serializersModule = ... } vasitəsilə qlobal olaraq bütün tip nümunələrinə bağlamaq. İkinci üsul daxili tiplər (Date, UUID) üçün üstünlük təşkil edir ki, hər sahədə annotasiya yazmaq lazım olmasın.

kotlin
// java.util.Date üçün xüsusi serializator
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

object DateSerializer : KSerializer<Date> {
    private val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US)

    override val descriptor: SerialDescriptor =
        PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING)

    override fun serialize(encoder: Encoder, value: Date) {
        encoder.encodeString(dateFormat.format(value))
    }

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

// Xüsusi serializatordan istifadə
@Serializable
data class Event(
    val title: String,
    @Serializable(with = DateSerializer::class)
    val date: Date
)

fun main() {
    val json = Json { prettyPrint = true }
    val event = Event("Buraxılış", Date())
    println(json.encodeToString(event))
}

Nümunədə DateSerializer java.util.Date-i ISO 8601 sətirinə çevirir. Xüsusi serializator olmadan kotlinx.serialization Date ilə işləyə bilməz — bu, Kotlin standart kitabxanasına daxil olmayan tipdir. Konkret sahədə @Serializable(with = DateSerializer::class) serializatoru yalnız bu sahə üçün qoşur. Bütün Date-lərin qlobal qeydiyyatı üçün Json { serializersModule = SerializersModule { contextual(DateSerializer) } } istifadə edin.

Serializasiya formatları: JSON, ProtoBuf, CBOR, HOCON

kotlinx.serialization təkcə JSON ilə məhdudlaşmır. Kitabxana dörd daxili formatı dəstəkləyir, hər biri öz modulu və konfiqurasiyası ilə. JSON (kotlinx-serialization-json) — universal, insan tərəfindən oxuna bilən, REST API üçün uyğun. ProtoBuf (kotlinx-serialization-protobuf) — ikilik, yığcam, məcburi sxemlə, yüksək yüklü mikroxidmətlər üçün. CBOR (kotlinx-serialization-cbor) — JSON-un ikilik analoqu, məhdud trafikli IoT və mobil cihazlar üçün əlverişli. HOCON (kotlinx-serialization-hocon) — TypeSafe Config ilə uyğun konfiqurasiya formatı.

FormatModulTipSxemTipik tətbiq
JSONkotlinx-serialization-jsonMətnKönüllüREST API, məlumat saxlama
ProtoBufkotlinx-serialization-protobufİkilikMəcburi (.proto)Mikroxidmətlər, gRPC
CBORkotlinx-serialization-cborİkilikKönüllüIoT, mobil cihazlar
HOCONkotlinx-serialization-hoconMətnKönüllüKonfiqurasiya faylları

ProtoBuf .proto fayllarında sxemin təyin edilməsini tələb edir, lakin kotlinx-serialization-protobuf Kotlin siniflərini birbaşa @Serializable-dan .proto olmadan yaradır. Bu, inkişafı sadələşdirir: data class-ı annotasiya etmək və ProtoBuf.encodeToByteArray() istifadə etmək kifayətdir. CBOR xüsusilə NFC və ya BLE vasitəsilə yığcam ikilik məlumat ötürmək lazım olduqda Android çərçivəsi üçün aktualdır. CBOR mesajının ölçüsü eyni məlumat dəsti ilə JSON-dan orta hesabla 20-30% kiçikdir.

Layihə üçün format seçimi

Mobil tətbiqdə REST API üçün JSON optimaldır — əlavə alətlər olmadan sazlanır, jurnallarda oxunur və istənilən backend ilə uyğundur. Əgər tətbiq mikroxidmətlər arasında böyük həcmdə məlumat ötürürsə (yüzlərlə meqabayt) — ProtoBuf ikilik kodlaşdırma sayəsində 5 dəfəyə qədər sürət qazandırar. Parametrləri fayllarda saxlamaq üçün HOCON və ya JSON istifadə edin. Sərt trafik məhdudiyyəti olan cihazlar (IoT sensorları) üçün — CBOR.

kotlinx.serialization ilə işləyərkən tipik səhvlər

Birinci səhv — deserializasiya zamanı naməlum açarlara məhəl qoymamaq. Əgər server yeni sahə əlavə edibsə və ignoreUnknownKeys = false-dursa, tətbiq SerializationException ilə çəkiləcək. Defolt olaraq bu bayraq söndürülüb. Həll: API dəyişikliklərinə davamlı olmaq üçün istehsal kodunda həmişə Json { ignoreUnknownKeys = true } təyin edin.

İkinci səhv — data class-da internal və ya private sahələrin serializasiyası. Kotlin data class-da primary constructor-dakı bütün sahələr defolt olaraq serializasiya olunur. Əgər sahə həssas məlumat ehtiva edirsə (şifrə, token), onu @Transient ilə qeyd etmək və ya primary constructor-dan çıxarmaq lazımdır. @Transient sahəni JSON-dan tamamilə çıxarır, lakin constructor-da xətaya səbəb ola bilər — belə sahəni @Transient ilə sinif gövdəsində təyin etmək daha yaxşıdır.

Üçüncü səhv — sealed class olmadan polimorf serializasiya. sealed əvəzinə open class istifadə edilərsə, kotlinx.serialization serializersModule-də bütün varislərin açıq qeydiyyatını tələb edir. sealed class-dan fərqli olaraq, kompilator bütün varisləri bilir, open class isə ixtiyari genişləndirməyə imkan verir — kitabxana bütün alt tipləri avtomatik müyən edə bilməz. Qeydiyyat Json { serializersModule = SerializersModule { polymorphic(Base::class) { subclass(Derived::class) } } } vasitəsilə aparılır.

Kitabxana versiyalaşdırma xətası

kotlinx.serialization versiyası Kotlin versiyası ilə uyğun olmalıdır. JetBrains uyğunluq cədvəlini dərc edir: kotlinx-serialization 1.6.x Kotlin 1.9.x ilə, 1.7.x Kotlin 2.0.x və 2.1.x ilə uyğundur. Versiyaların uyğunsuzluğu „Symbol ‘serializer’ is missing” kimi anlaşılmaz kompilasiya xətalarına səbəb olur. Həmişə cari versiyanı mavenCentral-də və ya layihənin GitHub repozitoriyasında yoxlayın.

Tez-tez verilən suallar

kotlinx.serialization Gson və Moshidən nə ilə fərqlənir?

kotlinx.serialization KSP vasitəsilə kompilasiya zamanı kod yaradılmasından istifadə edir, Gson və Moshi isə icra zamanı refleksiyasından. Bu, performansda üstünlük (Gson-dan 3-5 dəfə sürətli) və tip təhlükəsizliyi təmin edir. Gson annotasiyasız istənilən sahəni serializasiya edir ki, bu da məlumat sızıntısına səbəb ola bilər. kotlinx.serialization açıq @Serializable annotasiyası tələb edir ki, bu da daha təhlükəsizdir. Moshi də codegen-i dəstəkləyir, lakin yalnız JVM və Android üçün.

kotlinx.serialization Kotlin Multiplatform-u dəstəkləyirmi?

Bəli, kotlinx.serialization JetBrains-in rəsmi çoxplatformalı kitabxanasıdır. O, Kotlin/JVM (Android, Backend), Kotlin/Native (iOS), Kotlin/JS (Web, React) və Kotlin/Wasm üzərində işləyir. API bütün platformalar üçün vahiddir: @Serializable + Json.encodeToString() hər yerdə eyni işləyir. iOS üçün əlavə tənzimləmə tələb olunmur — Kotlin/Native serializasiya olunmuş kodu yerli ikilik fayla kompilasiya edir.

JSON-da null sahələrini necə idarə etməli?

Nullable sahələr (String?) JSON-da dəyər yoxdursa və ya null göstərilirsə, null kimi deserializasiya olunur. Defolt qiyməti olmayan non-nullable sahələr (String) üçün JSON-da sahənin olmaması SerializationException-a səbəb olur. Null dəyərlərin JSON-a düşməməsini istəyirsinizsə, Json { encodeDefaults = false } konfiqurasiya edin. Bu, default-a bərabər olan bütün sahələri (nullable üçün null daxil olmaqla) çıxışdan çıxaracaq.

Server snake_case sahələri göndərirsə nə etməli?

@SerialName(“snake_case_name”) istifadə edin adı Kotlin formatından fərqlənən hər sahədə. Alternativ olaraq, Kotlin 2.0+ üçün Json { namingStrategy = JsonNamingStrategy.SnakeCase } mövcuddur — camelCase ↔ snake_case avtomatik çevrilməsi. Bu tənzimləmə bütün sahələrə birdən tətbiq olunur. Qismən fərdiləşdirmə lazımdırsa, @SerialName-i qlobal strategiya ilə birləşdirin.

Kotlin Flow və ya korutinləri serializasiya etmək olarmı?

Xeyr, Flow və korutinlər birbaşa serializasiya olunmur — onlar asinxron icranı təmsil edir, məlumatı deyil. Flow-dan məlumat ötürmək üçün onu korutində .toList() vasitəsilə kolleksiyaya yığmaq və kolleksiyanı serializasiya etmək lazımdır. Eynilə, Job, Deferred və ya Continuation serializasiya oluna bilməz. Yalnız data class-ları — davranış məntiqi olmayan məlumat modellərini serializasiya edin.

Nəticələr

  • kotlinx.serialization — @Serializable vasitəsilə kompilasiya zamanı serializasiya, refleksiyasız, Gson-dan 5 dəfəyə qədər yüksək performans
  • @Serializable, @SerialName, @Transient — sahə və sinif serializasiyasını konfiqurasiya etmək üçün əsas annotasiyalar
  • Json {} builder JSON-u konfiqurasiya edir: ignoreUnknownKeys, prettyPrint, coerceInputValues, encodeDefaults
  • Sealed class və polimorf serializasiya — əlavə kod olmadan tip iyerarxiyalarının qüsursuz dəstəyi
  • KSerializer — qeyri-standart tiplər (Date, Bitmap, UUID) üçün xüsusi serializatorlar interfeysi
  • Dörd format: JSON, ProtoBuf, CBOR, HOCON — modullarla qoşulur, API bütünlər üçün vahiddir
  • Çoxplatformalılıq — JVM, Native, JS və Wasm üçün vahid kod; KMM və ümumi modullar üçün kritikdir

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun