CodeGym /Kurslar /Kotlin SELF /kotlinx.serialization-in qosulmasi ve @Serializable annot...

kotlinx.serialization-in qosulmasi ve @Serializable annotasiyasi

Kotlin SELF
Səviyyə, Dərs
Mövcuddur

1. Seriyalizasiya doğrudanmı lazımdır?

Yeni başlayan üçün ilk istək tam məntiqlidir: “Mən sadəcə println(user) edib bunu fayla yaza bilmərəm? Axı orada artıq mətn var!” Və məhz burada klassik tələ başlayır: mətn — həmişə məlumat demək deyil. Daha dəqiqi, mətn məlumat ola bilər, amma yalnız onda ki, onun aydın format qaydaları var və biz sonradan obyekti “qəhvə falı” ilə təxmin etmədən geri bərpa edə bilirik.

toString() data class üçün həqiqətən də belə tipli gözəl sətir verir: User(id=1, name=Ada). Amma bu, format müqaviləsi (contract) deyil, debuq üçün rahatlıqdır. Proqramın növbəti versiyasında siz sahəni yenidən adlandıracaqsınız, parametrlərin sırasını dəyişəcəksiniz, yeni sahə əlavə edəcəksiniz — və köhnə fayllar “qədim sivilizasiyanın artefaktları”na çevriləcək; nəticədə elə sizin proqramınız onları oxuya bilməyəcək.

Buna görə də seriyalizasiya lazımdır: biz istəyirik ki, obyekti saxlama/mübadilə formatına çevirə bilək, sonra da aydın qaydalarla onu geri bərpa edək. Bu gün üçün JSON seçilib və bu yaxşı xəbərdir: JSON gözlə oxunur, faylda adi mətn kimi saxlanır və onu demək olar ki, bütün dillər anlayır.

2. kotlinx.serialization necə qurulub

kotlinx.serialization sadəcə “mənə JSON düzəlt” funksiyaları toplusu deyil. Bu texnologiyanın vacib hissəsi ondadır ki, Kotlin kompilyator plagini qoşur və o, sinifləriniz üçün seriyalizasiya kodu generasiya edə bilir. Yəni siz @Serializable data class User(...) yazırsınız, kompilyator isə JSON-a çevirməyi və geri çevirməyi bilən “görünməz köməkçilər” yaradır.

Bu bir az mistik səslənir, amma ideya çox praktikdir: seriyalizasiyanı əl ilə yazmaq demək olar ki, həmişə xətalarla bitir; xüsusən də sizdə iç-içə obyektlər, siyahılar, nullable-sahələr və default dəyərlər olanda.

Balaca sxem — “başda oturtsun” deyə, nəyin harada baş verdiyini göstərir:

flowchart TD
    A[Sizin kod: data class + @Serializable] --> B[Kotlin kompilyatoru + serialization plugin]
    B --> C[Seriyalizatorun generasiya olunmus kodu]
    C --> D[Runtime kitabxanasi kotlinx-serialization-json]
    D --> E[JSON metni / JSON agaci]

3. Gradle-da qoşulma

Seriyalizasiyanın qoşulması yeni başlayanlarda demək olar ki, həmişə iki səbəbdən biri ilə “qırılır”: ya kitabxananı əlavə edirlər, amma kompilyator plaginini unudurlar, ya da əksinə. Ona görə başda sadə qaydanı saxlayırıq: həm asılılıq (dependency), həm də plagin lazımdır. Və bəli, bu elə məqamlardandır ki, Gradle xatırladır: “mən pis deyiləm, sadəcə mən konfiqəm”.

Seriyalizasiya plaginini qoşuruq

Gradle üzərində Kotlin/JVM layihəsində ( build.gradle.kts ilə) adətən seriyalizasiya plaginini əsas kotlin plagininin yanında qoşurlar. Vacibdir ki, seriyalizasiya plagininin versiyası layihənin Kotlin plagininin versiyası ilə üst-üstə düşsün (bizim kursda — Kotlin 2.3). Versiyalar ayrılıb getsə, çox qəribə xətalar ala bilərsiniz və hətta kompilyatorun özü də “çaşqın” qala bilər.

build.gradle.kts-dən fraqment nümunəsi (qısa, yalnız mahiyyət):

plugins {
    kotlin("jvm") version "2.3.0"
    kotlin("plugin.serialization") version "2.3.0"
}

Əgər layihənizdə Kotlin versiyası "2.3.0" deyil, başqadırsa (məsələn, "2.3.10"), burada da eyni olmalıdır.

JSON moduluna asılılıq qoşuruq

İndi Json-u və JSON-spesifik hər şeyi verən runtime kitabxananı qoşaq. kotlinx.serialization-in versiyaları öz “həyatını” yaşayır, ona görə konkret rəqəm zamanla dəyişə bilər — amma prinsip eynidir: kotlinx-serialization-json-u dependencies-ə əlavə edirik.

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0")
}

Əgər “bəs dəqiq "1.7.0"?” deyə soruşursunuzsa — tədris nümunəsi üçün konkret rəqəmdən daha vacibi quruluşdur. Versiyanı dəyişmək olar, amma plagin və Kotlin bir-biri ilə “dost” olmalıdır, yoxsa məclis başlamamış bitəcək.

Layihənin sinxronizasiyasi

Gradle faylında düzəlişlərdən sonra sinxronizasiya etmək lazımdır (IntelliJ-də adətən “Load Gradle Changes” / “Sync” düyməsi çıxır). Bunu etməsəniz, IDE siz hər şeyi düzgün yazsanız belə Unresolved reference göstərməyə davam edə bilər. Bu mistika deyil — sadəcə Gradle hələ asılılıqları yükləməyib və layihə modelini yenidən qurmayıb.

4. @Serializable annotasiyasi ve modellər

“Annotasiya” sözü asanlıqla “səhər yeməyində istisna yeyən böyük proqramçılar üçün nəsə” kimi səslənə bilər. Amma mahiyyətcə annotasiya — sadəcə koddakı nişandır. O, funksiya kimi “icra olunmur”. O, alətlərə (kompilyatora, kitabxanalara, IDE-yə) deyir: “bu elementi xüsusi qaydada emal etmək lazımdır”.

Bizim halda @Serializable — nişandır: “bu sinif üçün seriyalizator generasiya olunmalıdır”. Sonra isə kompilyator plagini öz işini görür.

Minimal nümunə

import kotlinx.serialization.Serializable

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

Burada vacib olan odur ki, @Serializable sinifin üstünə qoyulur. Bu gün onu ayrıca sahələrin üzərinə qoymaq lazım deyil (formatın incə sazlamaları sonra olacaq).

Expense modeli

Nümunələr “vakuumda” olmasın deyə, şərti praktik konsol tətbiqini davam etdirək — qoy bu sadə xərc izləyicisi (expense tracker) olsun. Əvvəllər xərcləri MutableList<Expense>-də saxlaya və konsola çap edə bilərdik. İndi isə vəziyyəti JSON faylında saxlamaq üçün hazırlıq görürük (amma encode/decode artıq növbəti leksiyada olacaq).

Xərc modelindən başlayaq:

import kotlinx.serialization.Serializable

@Serializable
data class Expense(
    val id: Int,
    val title: String,
    val amount: Int
)

Sahələr maksimum sadədir: Int və String. Bu qəsdən belə edilib: başlanğıcda model nə qədər sadə olsa, seriyalizasiyanın başa düşmədiyi tipə görə problem “tutmaq” ehtimalı bir o qədər az olur.

AppState modeli

İndi tətbiqin vəziyyəti modeli əlavə edək ki, sonradan təkcə xərclər siyahısını yox, məsələn növbəti id-ni də saxlaya bilək:

import kotlinx.serialization.Serializable

@Serializable
data class AppState(
    val nextId: Int,
    val expenses: List<Expense>
)

Vacib məqama diqqət edin: əgər AppState özündə Expense saxlayırsa, deməli Expense də seriyalizasiya oluna bilən olmalıdır. Əks halda kompilyator “haqlı olaraq etiraz edəcək”: “bu tipli sahəni necə seriyalizasiya edəcəyimi bilmirəm”.

Nullable-sahələr və default dəyərlər

Praktikada məlumatlar tez-tez natamam olur: şərh (comment) olmaya bilər, əlavə təsvir boş ola bilər, hansısa sahə isə proqramı genişləndirdikdə sonradan yarana bilər. Ona görə nullable tiplər və default dəyərlər — normal alətdir; sadəcə başa düşmək vacibdir ki, onlar məlumatların JSON-da necə görünəcəyinə təsir edir (dəqiq sazlamaları Json { ... } haqqında leksiyada müzakirə edəcəyik).

Xərclərə qeyri-məcburi şərh və default dəyəri olan valyuta əlavə edək:

import kotlinx.serialization.Serializable

@Serializable
data class Expense(
    val id: Int,
    val title: String,
    val amount: Int,
    val currency: String = "USD",
    val note: String? = null
)

Məna belədir: köhnə qeydlərdə note olmaya bilər, amma default valyuta həmişə var. Bu, hər “asqırıqdan” qırılmayan “dayanıqlı” məlumat formatına doğru yaxşı addımdır.

5. Sürətli yoxlama və layihə strukturu

Bəzən elə gəlir ki, hər şey qoşulub, amma layihənin içində plagin aktivləşməyib (və ya Gradle sinxronizasiya olunmayıb). Sadə test lazımdır ki, bunu yoxlasın: “kompilyator doğrudan da seriyalizator generasiya edib”.

Plaginin həqiqətən işlədiyini yoxlayırıq

Belə testlərdən biri — sinifdəki serializer()-a müraciət etməkdir. Seriyalizator generasiya olunubsa, kod kompilyasiya olunur.

import kotlinx.serialization.Serializable

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

fun main() {
    val s = User.serializer()
    println(s.descriptor.serialName) // User
}

Əgər burada kompilyasiya xətası alırsınızsa, səbəb demək olar ki, həmişə qoşulmadadır: ya kotlin("plugin.serialization")-i unutmusunuz, ya asılılıq yüklənməyib, ya da layihə yenidən sinxronizasiya olunmayıb. Və bəli, bu nadir hallardandır ki, “layihəni yenidən build etmək” şamanlıq yox, real diaqnostikadır.

Modelləri harada saxlamaq və “zibil yığını” yaratmamaq

Seriyalizasiya əlavə edəndə layihə boyu hər yerə @Serializable “sürtmək” istəyi yaranır, sinifləri də main-in yanında saxlamaq, çünki “belə daha tezdir”. Tezdir — bəli, amma elə ilk anda ki, Expense-in harda olduğunu, AppState-in harda olduğunu tapa bilməyəcəksiniz və niyə onların üç yerdə fərqli olduğunu anlamayacaqsınız.

İndi artıq yaxşı vərdiş: modelləri ayrı paketdə saxlamaq, məsələn app.model və ya tracker.model. Onda fayllarınız proqnozlaşdırılan görünəcək: Expense.kt, AppState.kt və hər birində — bir əsas tip.

Üstəlik, model ayrıca olanda daha asan görürsünüz: “aha, yeni sahə əlavə etdim — deməli məlumat formatı dəyişdi”. Bu, hətta tədris layihəsində də faydalıdır.

6. kotlinx.serialization qoşulanda tipik xətalar

Xəta №1: asılılığı əlavə etdiniz, amma seriyalizasiya plaginini unutdunuz.
Çox yayılmış ssenari: siz implementation("...kotlinx-serialization-json...")-u qoşdunuz, @Serializable yazdınız, amma IDE yenə də “danlayır” və ya User.serializer() tapılmır. Bu ona görədir ki, kotlin("plugin.serialization") olmadan kompilyator seriyalizator generasiya etmir — təkcə kitabxana bütün prosesi “çəkib apara” bilmir. Plagini əlavə edib Gradle sinxronizasiyası edərək aradan qaldırılır.

Xəta №2: Kotlin plagini ilə serialization plagininin versiyaları uyğun gəlmir.
Buradakı “ağrı” ondadır ki, xəta “mövzuya uyğun olmayan” kimi görünə bilər: bəzən bu, kompilyatorun qəribə mesajları və ya build-in sizin kodla əlaqəsi olmayan mərhələdə dayanması olur. Praktik qayda sadədir: layihə Kotlin 2.3.x üzərindədirsə, kotlin("plugin.serialization") da 2.3.x olmalıdır.

Xəta №3: “qutudan” dəstəklənməyən mürəkkəb tipli sahəsi olan sinifi seriyalizasiya edirsiniz.
Məsələn, siz File, Path, Instant tipli sahə əlavə edirsiniz, və ya @Serializable olmadan hər hansı öz sinifinizi əlavə edirsiniz. Kompilyator deyəcək: “bunu necə seriyalizasiya edəcəyimi bilmirəm”. Bu kapriz deyil: seriyalizasiya hər sahə üçün dəqiq alqoritm tələb edir. Başlanğıcda modelləri sadə saxlayın: ədədlər, sətrlər, siyahılar, nullable. Mürəkkəb tiplər ya daha sadə görünüşə “bükülür”, ya da ayrıca yanaşma tələb edir (amma bu günkü leksiyanın mövzusu deyil).

Xəta №4: yanlış Serializable import etmisiniz.
Kotlin/Java dünyasında bir neçə Serializable var. Bizə məhz kotlinx.serialization.Serializable lazımdır. Əgər siz təsadüfən java.io.Serializable import etmisinizsə, kompilyator seriyalizasiya plagini bunu “görməyəcək”, sonra da “niyə işləmir, axı Serializable yazmışam” səviyyəsində tapmacalar başlayacaq. Import-u yoxlayın — xırdalıqdır, amma ən hiyləgərlərdəndir.

Xəta №5: @Serializable-in avtomatik olaraq məlumatı fayla yazacağını gözləmək.
Annotasiya sinifi “seriyalizasiya üçün yararlı” edir, amma özü-özlüyündə heç nə yazmır. JSON yazmaq/oxumaq ayrıca addımdır: Json kodeki, encode/decode funksiyaları və fayl əməliyyatları. Bu gün fundamenti qoyuruq (modellər + qoşulma), “obyekt ↔ JSON ↔ fayl” praktiki pipeline isə növbəti mərhələ olacaq.

1
Tapşırıq
Kotlin SELF, səviyyə, dərs
Bağlanıb
Xərclər kateqoriyaları
Xərclər kateqoriyaları
1
Tapşırıq
Kotlin SELF, səviyyə, dərs
Bağlanıb
Tip təklifi
Tip təklifi
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION