kotlinx.serialization: mi ez, annotációk és szerializáció JSON-ba

Szerző: IT Sectr Megjelenés: 2026-03-15 Olvasási idő: 12 perc

kotlinx.serialization — egy többplatformos könyvtár a JetBrainstól Kotlin-objektumok JSON, ProtoBuf, CBOR és más formátumokba való átalakításához reflexió nélkül. A Gsonnal és Moshival ellentétben a szerializátor kódot a fordítás során hozza létre a @Serializable annotáción keresztül, ami magas teljesítményt és típusbiztonságot nyújt. A GitHub Kotlin/kotlinx.serialization szerint a könyvtár támogatja a Kotlin/JVM, Kotlin/Native, Kotlin/JS és Kotlin/Wasm platformokat.

Főbb pontok

  • kotlinx.serialization — fordítási idejű szerializáció: a kód a fordítás során jön létre, reflexió nem használt
  • @Serializable — a fő annotáció, amely elindítja a szerializátor generálását az osztály számára
  • Json {} builder — JSON-konfiguráció a Json { ignoreUnknownKeys = true; prettyPrint = true } segítségével
  • Többplatformosság — a könyvtár JVM, Native, JS és Wasm platformokon működik az API megváltoztatása nélkül
  • Egyedi szerializátorok — a KSerializer interfészen keresztül nem szabványos adatformátumokhoz

Mi az a kotlinx.serialization

kotlinx.serialization — egy beépített szerializációs könyvtár Kotlinhoz, amelyet a JetBrains fejlesztett a hivatalos Kotlin-ökoszisztéma részeként. Fő különbsége a harmadik féltől származó megoldásoktól (Gson, Moshi, Jackson) az, hogy nem használ reflexiót futásidőben. Ehelyett a szerializátor kódja a fordítás során jön létre a Kotlin Symbol Processing (KSP) vagy a Kotlin Compiler Plugin segítségével. Ez akár 3-5-szörös teljesítménynövekedést biztosít a Gsonhoz képest, és garantálja a típusbiztonságot.

A könyvtár hivatalosan négy formátumot támogat: JSON (a kotlinx-serialization-json modulon keresztül), ProtoBuf (kotlinx-serialization-protobuf), CBOR (kotlinx-serialization-cbor) és HOCON (kotlinx-serialization-hocon). A formátumok külön függőségekként kerülnek hozzáadásra a build.gradle.kts fájlban, ami lehetővé teszi, hogy ne húzzon be felesleges könyvtárakat a projektbe. Minden formátumhoz saját konfigurációs paraméterkészlet tartozik.

Többplatformosság — a könyvtár kulcsfontosságú jellemzője. Ugyanaz az osztály @Serializable annotációval minden célplatformon működik: JVM (Android, Backend), Native (iOS), JS (Web, React) és Wasm (WebAssembly). A fejlesztőnek nem kell különböző szerializációs implementációkat írnia minden platformhoz — a kód egységes marad. Ez különösen értékes a Kotlin Multiplatform Mobile (KMM) projektekben, ahol a megosztott kód Android és iOS között oszlik meg.

Hogyan működik a fordítási idejű kódgenerálás

Kódgenerálás a kotlinx.serializationban három szakaszban történik. Az első szakaszban a Kotlin-fordító észleli a @Serializable annotációt egy osztályon, és továbbítja a Kotlin Symbol Processing (KSP) bővítménynek. A második szakaszban a KSP létrehoz egy szerializátor objektumot, amely megvalósítja a KSerializer interfészt. A harmadik szakaszban a létrehozott kód a projekt forráskódjával együtt fordul le. Ennek eredményeként ezen szakaszok egyike sem fut le az alkalmazás futása során.

A létrehozott szerializátor közvetlenül az osztály mezőivel dolgozik azok getterén és setterén keresztül, reflexió nélkül. Ez azt jelenti, hogy a private módosítóval rendelkező mezők is szerializálódnak, ha @Serializable-val vannak jelölve. Ennek a megközelítésnek a teljesítménye közel áll a kézi szerializációhoz: egyszerű osztályok (5-10 mező) esetén a szerializációs idő 10-50 mikroszekundum, összetett objektumgráfok esetén — akár 200 mikroszekundum 1000 objektumonként.

A könyvtár csatlakoztatásához egy Android vagy Kotlin/JVM projektben hozzá kell adni a bővítményt és a függőségeket a build.gradle.kts fájlban. A Kotlin verziójának megfelelő org.jetbrains.kotlin.plugin.serialization bővítmény aktiválja a kódgenerálást. A kotlinx-serialization-json könyvtár a dependencies szakaszban kerül hozzáadásra egy Kotlin verziójától független verzióval.

kotlin
// build.gradle.kts — a kotlinx.serialization csatlakoztatása
plugins {
    val kotlinVersion = "2.1.0"
    kotlin("jvm") version kotlinVersion
    kotlin("plugin.serialization") version kotlinVersion
}

dependencies {
    // Fő szerializációs modul
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")

    // További formátumok
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:1.7.3")
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-cbor:1.7.3")
}

Alapvető használat: szerializáció JSON-ba

JSON — a legnépszerűbb formátum a kotlinx.serializationban. Egy objektum szerializálásához elegendő a @Serializable annotációt elhelyezni egy data class-on, és meghívni a Json.encodeToString() metódust. A deszerializációhoz — Json.decodeFromString() a típus megadásával. A könyvtár automatikusan kezeli a null mezőket, listákat, beágyazott objektumokat és enumokat. Az osztály összes mezője alapértelmezés szerint kötelező, hacsak másként nincs megadva.

A JSON-konfiguráció a Json {} builder segítségével történik. A konstruktorban átadható az ignoreUnknownKeys = true az ismeretlen mezők figyelmen kívül hagyásához deszerializációkor, a prettyPrint = true a formázott kimenethez, a coerceInputValues = true a helytelen értékek alapértelmezett értékekre való konvertálásához. Szintén elérhetők az encodeDefaults (alapértelmezett értékű mezők szerializálása) és classDiscriminator (a mező neve polimorf szerializációhoz) beállítások.

kotlin
// Példa JSON szerializációra és deszerializációra
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")
    )

    // Szerializáció JSON-ba prettyPrint segítségével
    val json = Json { prettyPrint = true }
    val jsonString = json.encodeToString(project)
    println(jsonString)
    /*
    {
        "name": "kotlinx.serialization",
        "stars": 7200,
        "isActive": true,
        "languages": ["Kotlin", "Java"]
    }
    */

    // Deszerializáció JSON-ból
    val decoded = json.decodeFromString<Project>(jsonString)
    println(decoded.name)  // kotlinx.serialization
}

A példa a szerializáció és deszerializáció alapvető ciklusát mutatja be. A @Serializable annotációval ellátott Project data class automatikusan megkapja az encodeToString és decodeFromString metódusokat. Az isActive mező alapértelmezett értéke true — ha ez a mező hiányzik a JSON-ból, az alapértelmezett érték kerül használatra. Ha ismeretlen mezők érkeznek a JSON-ban ignoreUnknownKeys = true nélkül, SerializationException kivétel dobódik.

Sealed class polimorf szerializációja

Sealed class — a kotlinx.serialization egyik legerősebb használati esete. A könyvtár támogatja a polimorf szerializációt sealed class hierarchiákhoz külön konfiguráció nélkül: elegendő a sealed class-t és annak összes leszármazottját @Serializable-val jelölni. A szerializáció során a „type” mező (classDiscriminator segítségével konfigurálható) hozzáadásra kerül, amely alapján a deszerializáció során a konkrét típus meghatározásra kerül.

kotlin
// Sealed class polimorf szerializációja
@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}")
    }
}

A sealed class polimorf szerializációja különösen hasznos az API kliensekben, ahol a szerver különböző típusú válaszokat ad vissza. Kotlinx.serialization nélkül kézi deszerializátort kellene írni when segítségével a diszkriminátor mező alapján. A könyvtárral ez egyetlen annotációval történik. A classDiscriminator lehetővé teszi a marker mező nevének (alapértelmezés szerint „type”) megváltoztatását bármilyen, a szerver által várt értékre.

A kotlinx.serialization annotációi: teljes áttekintés

A könyvtár egy sor annotációt kínál a szerializáció finomhangolásához. A fő annotáció a @Serializable az osztály számára. További annotációk: @SerialName a mező JSON-beli nevének megadásához (ha eltér a Kotlin-névtől), @Transient a mező szerializációból való kizárásához, @Required a JSON-ban kötelezően jelenlévő mezőhöz, @EncodeDefault az alapértelmezett értékű mező kényszerített szerializálásához.

AnnotációCélPélda
@SerializableEngedélyezi a szerializátor generálását az osztály számára@Serializable data class User
@SerialNameMegadja a mező alternatív nevét a formátumban@SerialName(„user_name”) val name: String
@TransientKizárja a mezőt a szerializációból@Transient val cache: MutableMap
@RequiredA mező kötelező a JSON-ban deszerializációkor@Required val id: String
@EncodeDefaultSzerializálja a mezőt még alapértelmezett értékkel is@EncodeDefault val type: Type = Type.A
@SerializerEgyedi szerializátort kapcsol az osztályhoz@Serializer(forClass = Date::class)

A @SerialName annotáció kritikus fontosságú olyan API-kkal való munka során, ahol a mezőnevek snake_case, a Kotlin stílus pedig camelCase. Például a szerver „user_id”-t küld, a Kotlin-kódban pedig userId szerepel. A @SerialName(„user_id”) megoldja ezt a problémát további mapperek nélkül. A @Transient olyan mezőkhöz hasznos, amelyeket nem kell elküldeni a szerverre — például ideiglenes számított értékek vagy gyorsítótár.

@Required mint alternatíva a nullable mezőkhöz

Alapértelmezés szerint a kotlinx.serializationban minden mező kötelező. Ha egy mező hiányozhat a JSON-ból, nullázhatóvá kell tenni (String?) vagy alapértelmezett értéket kell beállítani (val name: String = „”). Vannak azonban olyan helyzetek, amikor a mező nem nullázható Kotlinban, de hiányozhat a JSON-ból az API verziókezelése miatt. Ebben az esetben a @Required SerializationException-t dob a mező hiányakor, míg az alapértelmezett érték hiba nélkül tölti ki a default-ot.

Egyedi szerializátorok: KSerializer és kézi vezérlés

KSerializer — interfész, amelyet a kotlinx.serialization összes szerializátora megvalósít. Ha a szabványos kódgenerálás nem megfelelő (például Date, Bitmap vagy egy adott bináris formátum kezeléséhez), megírhatja saját szerializátorát. Ehhez meg kell valósítania a serialize() és deserialize() metódusokat, valamint meg kell adnia egy deskriptort — a struktúra leírását a formátum sémájához.

Az egyedi szerializátorok kétféleképpen csatlakoztathatók: a @Serializable(with = MySerializer::class) annotáción keresztül egy adott osztályhoz kapcsolva, vagy globálisan a Json { serializersModule = ... } segítségével a típus összes példányához kapcsolva. A második mód előnyösebb a beépített típusok (Date, UUID) esetében, hogy ne kelljen minden mezőn annotációt írni.

kotlin
// Egyedi szerializátor java.util.Date-hez
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())
    }
}

// Egyedi szerializátor használata
@Serializable
data class Event(
    val title: String,
    @Serializable(with = DateSerializer::class)
    val date: Date
)

fun main() {
    val json = Json { prettyPrint = true }
    val event = Event("Kiadás", Date())
    println(json.encodeToString(event))
}

A példában a DateSerializer a java.util.Date-t ISO 8601 stringgé alakítja. Egyedi szerializátor nélkül a kotlinx.serialization nem tud a Date-tel dolgozni — ez egy olyan típus, amely nem része a szabványos Kotlin könyvtárnak. A @Serializable(with = DateSerializer::class) egy adott mezőn csak arra a mezőre kapcsolja a szerializátort. Az összes Date globális regisztrációjához használja a Json { serializersModule = SerializersModule { contextual(DateSerializer) } } kifejezést.

Szerializációs formátumok: JSON, ProtoBuf, CBOR, HOCON

kotlinx.serialization nem korlátozódik a JSON-ra. A könyvtár négy beépített formátumot támogat, mindegyik saját modullal és konfigurációval. JSON (kotlinx-serialization-json) — univerzális, ember által olvasható, REST API-hoz alkalmas. ProtoBuf (kotlinx-serialization-protobuf) — bináris, kompakt, kötelező sémával, nagy terhelésű mikroszolgáltatásokhoz. CBOR (kotlinx-serialization-cbor) — a JSON bináris megfelelője, korlátozott forgalmú IoT és mobileszközökhöz. HOCON (kotlinx-serialization-hocon) — konfigurációs formátum, kompatibilis a TypeSafe Config-gal.

FormátumModulTípusSchemaTipikus használat
JSONkotlinx-serialization-jsonSzövegesOpcionálisREST API, adattárolás
ProtoBufkotlinx-serialization-protobufBinárisKötelező (.proto)Mikroszolgáltatások, gRPC
CBORkotlinx-serialization-cborBinárisOpcionálisIoT, mobileszközök
HOCONkotlinx-serialization-hoconSzövegesOpcionálisKonfigurációs fájlok

ProtoBuf a séma .proto fájlokban történő meghatározását igényli, de a kotlinx-serialization-protobuf közvetlenül a @Serializable-ból generál Kotlin osztályokat .proto nélkül. Ez leegyszerűsíti a fejlesztést: elegendő egy data class-t annotálni és használni a ProtoBuf.encodeToByteArray() metódust. A CBOR különösen releváns az Android keretrendszer számára, amikor kompakt bináris adatokat kell továbbítani NFC-n vagy BLE-n keresztül. A CBOR üzenet mérete átlagosan 20-30%-kal kisebb, mint a JSON azonos adatkészlet esetén.

Formátum kiválasztása a projekthez

REST API-hoz mobilalkalmazásban a JSON az optimális — további eszközök nélkül debugolható, olvasható a naplókban és kompatibilis bármilyen backenddel. Ha az alkalmazás nagy mennyiségű adatot továbbít mikroszolgáltatások között (több száz megabájt) — a ProtoBuf akár 5-szörös sebességnövekedést biztosít a bináris kódolásnak köszönhetően. Beállítások fájlokban történő tárolásához használja a HOCON-t vagy JSON-t. Szigorú forgalmi korlátozásokkal rendelkező eszközökhöz (IoT érzékelők) — CBOR.

Gyakori hibák a kotlinx.serialization használatakor

Első hiba — ismeretlen kulcsok figyelmen kívül hagyása deszerializációkor. Ha a szerver új mezőt adott hozzá, és az ignoreUnknownKeys = false, az alkalmazás SerializationException-nel összeomlik. Alapértelmezés szerint ez a jelző ki van kapcsolva. Megoldás: mindig állítsa be a Json { ignoreUnknownKeys = true } értéket éles kódban, hogy ellenálló legyen az API-változásokkal szemben.

Második hiba — internal vagy private mezők szerializálása data class-ban. Kotlin data class-ban az elsődleges konstruktor összes mezője alapértelmezés szerint szerializálódik. Ha egy mező érzékeny adatokat tartalmaz (jelszó, token), @Transient jelöléssel kell ellátni vagy ki kell venni az elsődleges konstruktorból. A @Transient teljesen kizárja a mezőt a JSON-ból, de a konstruktorban hibát okozhat — jobb az ilyen mezőt az osztály törzsében @Transient jelöléssel definiálni.

Harmadik hiba — polimorf szerializáció sealed class nélkül. Ha open class-t használ sealed helyett, a kotlinx.serialization az összes leszármazott explicit regisztrációját igényli a serializersModule-ban. Ellentétben a sealed class-sal, ahol a fordító ismeri az összes leszármazottat, az open class tetszőleges bővítést tesz lehetővé — a könyvtár nem tudja automatikusan meghatározni az összes altípust. A regisztráció a Json { serializersModule = SerializersModule { polymorphic(Base::class) { subclass(Derived::class) } } } segítségével történik.

A könyvtár verziókezelési hibája

A kotlinx.serialization verziójának kompatibilisnek kell lennie a Kotlin verziójával. A JetBrains kompatibilitási táblázatot tesz közzé: a kotlinx-serialization 1.6.x kompatibilis a Kotlin 1.9.x-szel, 1.7.x — a Kotlin 2.0.x-szel és 2.1.x-szel. A verziók eltérése rejtélyes fordítási hibákat okoz, mint a „Symbol ‘serializer’ is missing”. Mindig ellenőrizze az aktuális verziót a mavenCentral-on vagy a projekt GitHub repozitóriumában.

Gyakran ismételt kérdések

Miben különbözik a kotlinx.serialization a Gsontól és a Moshitól?

kotlinx.serialization fordítási idejű kódgenerálást használ a KSP-n keresztül, míg a Gson és Moshi futásidejű reflexiót használ. Ez előnyt jelent a teljesítményben (3-5-ször gyorsabb, mint a Gson) és a típusbiztonságban. A Gson annotáció nélkül szerializál bármilyen mezőt, ami adatszivárgáshoz vezethet. A kotlinx.serialization explicit @Serializable annotációt igényel, ami biztonságosabb. A Moshi szintén támogatja a codegen-t, de csak JVM és Android esetén.

Támogatja a kotlinx.serialization a Kotlin Multiplatformot?

Igen, a kotlinx.serialization a JetBrains hivatalos többplatformos könyvtára. Működik Kotlin/JVM (Android, Backend), Kotlin/Native (iOS), Kotlin/JS (Web, React) és Kotlin/Wasm platformokon. Az API egységes minden platformon: a @Serializable + Json.encodeToString() mindenhol ugyanúgy működik. Az iOS-hez nincs szükség további beállításokra — a Kotlin/Native natív binárissá fordítja a szerializált kódot.

Hogyan kezeljük a null mezőket JSON-ban?

A nullázható mezők (String?) nullként deszerializálódnak, ha az érték hiányzik a JSON-ból vagy nullként van megadva. A nem nullázható mezők (String) alapértelmezett érték nélküli hiánya a JSON-ban SerializationException-t okoz. Ha azt szeretné, hogy a null értékek ne kerüljenek a JSON-ba, állítsa be a Json { encodeDefaults = false } értéket. Ez kizárja a kimenetből az összes default értékkel egyenlő mezőt (beleértve a null-t a nullázhatóknál).

Mit tegyünk, ha a szerver snake_case mezőket küld?

Használja a @SerialName(„snake_case_name”) annotációt minden olyan mezőn, amelynek neve eltér a Kotlin formátumtól. Alternatívaként Kotlin 2.0+ esetén elérhető a Json { namingStrategy = JsonNamingStrategy.SnakeCase } — automatikus camelCase ↔ snake_case konverzió. Ez a beállítás az összes mezőre egyszerre vonatkozik. Ha részleges testreszabásra van szükség, kombinálja a @SerialName-t a globális stratégiával.

Lehet szerializálni Kotlin Flow-t vagy coroutine-t?

Nem, a Flow és a korutinok nem szerializálhatók közvetlenül — aszinkron végrehajtást képviselnek, nem adatokat. A Flow-ból történő adatátvitelhez össze kell gyűjteni azokat egy gyűjteménybe a .toList() segítségével egy korutinban, és szerializálni a gyűjteményt. Hasonlóképpen, a Job, Deferred vagy Continuation sem szerializálható. Csak data class-okat — viselkedési logika nélküli adatmodelleket — szerializáljon.

Összefoglalás

  • kotlinx.serialization — fordítási idejű szerializáció @Serializable segítségével, reflexió nélkül, akár 5-ször nagyobb teljesítménnyel, mint a Gson
  • @Serializable, @SerialName, @Transient — kulcsfontosságú annotációk a mező- és osztályszerializáció konfigurálásához
  • Json {} builder konfigurálja a JSON-t: ignoreUnknownKeys, prettyPrint, coerceInputValues, encodeDefaults
  • Sealed class és polimorf szerializáció — zökkenőmentes típushierarchia-támogatás további kód nélkül
  • KSerializer — interfész egyedi szerializátorokhoz nem szabványos típusokhoz (Date, Bitmap, UUID)
  • Négy formátum: JSON, ProtoBuf, CBOR, HOCON — modulokkal csatlakoztatható, API egységes mindegyikhez
  • Többplatformosság — egységes kód JVM, Native, JS és Wasm platformokhoz; kritikus KMM-hez és megosztott modulokhoz

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is