kotlinx.serialization: co to je, anotace a serializace do JSON

Autor: IT Sectr Publikováno: 2026-03-15 Doba čtení: 12 min

kotlinx.serialization — multiplatformní knihovna od JetBrains pro převod Kotlin objektů do JSON, ProtoBuf, CBOR a dalších formátů bez použití reflexe. Na rozdíl od Gson a Moshi generuje kód serializátoru v fázi kompilace prostřednictvím anotace @Serializable, což poskytuje vysoký výkon a typovou bezpečnost. Podle GitHub Kotlin/kotlinx.serialization knihovna podporuje Kotlin/JVM, Kotlin/Native, Kotlin/JS a Kotlin/Wasm.

Hlavní body

  • kotlinx.serialization — serializace v čase kompilace: kód je generován ve fázi kompilace, reflexe se nepoužívá
  • @Serializable — hlavní anotace, která spouští generování serializátoru pro třídu
  • Json {} builder — konfigurace JSON přes Json { ignoreUnknownKeys = true; prettyPrint = true }
  • Multiplatformnost — knihovna funguje na JVM, Native, JS a Wasm bez změny API
  • Vlastní serializátory — přes rozhraní KSerializer pro nestandardní formáty dat

Co je kotlinx.serialization

kotlinx.serialization — je vestavěná serializační knihovna pro Kotlin, vyvinutá společností JetBrains jako součást oficiálního ekosystému Kotlin. Jejím hlavním rozdílem od řešení třetích stran (Gson, Moshi, Jackson) je, že nepoužívá reflexi za běhu. Místo toho je kód serializátoru generován ve fázi kompilace pomocí Kotlin Symbol Processing (KSP) nebo Kotlin Compiler Plugin. To poskytuje zvýšení výkonu až 3-5krát ve srovnání s Gson a zaručuje typovou bezpečnost.

Knihovna oficiálně podporuje čtyři formáty: JSON (prostřednictvím modulu kotlinx-serialization-json), ProtoBuf (kotlinx-serialization-protobuf), CBOR (kotlinx-serialization-cbor) a HOCON (kotlinx-serialization-hocon). Formáty se přidávají jako samostatné závislosti v build.gradle.kts, což umožňuje nezatahovat do projektu zbytečné knihovny. Pro každý formát existuje vlastní sada konfiguračních parametrů.

Multiplatformnost — klíčová vlastnost knihovny. Stejná třída s @Serializable pracuje na všech cílových platformách: JVM (Android, Backend), Native (iOS), JS (Web, React) a Wasm (WebAssembly). Vývojář nemusí psát různé implementace serializace pro každou platformu — kód zůstává jednotný. To je zvláště cenné v projektech Kotlin Multiplatform Mobile (KMM), kde je sdílený kód rozdělen mezi Android a iOS.

Jak funguje generování kódu v čase kompilace

Generování kódu v kotlinx.serialization probíhá ve třech fázích. V první fázi kompilátor Kotlin detekuje anotaci @Serializable na třídě a předá ji pluginu Kotlin Symbol Processing (KSP). Ve druhé fázi KSP generuje objekt serializátoru, který implementuje rozhraní KSerializer. Ve třetí fázi je generovaný kód zkompilován spolu se zdrojovým kódem projektu. Výsledkem je, že žádná z těchto fází není provedena za běhu aplikace.

Generovaný serializátor pracuje přímo s poli třídy prostřednictvím jejich getterů a setterů, bez reflexe. To znamená, že pole s modifikátorem private jsou také serializována, pokud jsou označena @Serializable. Výkon tohoto přístupu se blíží ruční serializaci: pro jednoduché třídy (5-10 polí) je doba serializace 10-50 mikrosekund, pro složité grafy objektů — až 200 mikrosekund na 1000 objektů.

Pro připojení knihovny v projektu Android nebo Kotlin/JVM je třeba přidat plugin a závislosti v build.gradle.kts. Plugin org.jetbrains.kotlin.plugin.serialization ve verzi odpovídající verzi Kotlin aktivuje generování kódu. Knihovna kotlinx-serialization-json se přidává v sekci dependencies s verzí nezávislou na verzi Kotlin.

kotlin
// build.gradle.kts — připojení kotlinx.serialization
plugins {
    val kotlinVersion = "2.1.0"
    kotlin("jvm") version kotlinVersion
    kotlin("plugin.serialization") version kotlinVersion
}

dependencies {
    // Hlavní modul serializace
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")

    // Další formáty
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:1.7.3")
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-cbor:1.7.3")
}

Základní použití: serializace do JSON

JSON — nejoblíbenější formát v kotlinx.serialization. Pro serializaci objektu stačí umístit anotaci @Serializable na data class a zavolat Json.encodeToString(). Pro deserializaci — Json.decodeFromString() s uvedením typu. Knihovna automaticky zpracovává null pole, seznamy, vnořené objekty a enumy. Všechna pole třídy jsou ve výchozím nastavení povinná, pokud není uvedeno jinak.

Konfigurace JSON se provádí prostřednictvím Json {} builder. Do konstruktoru lze předat ignoreUnknownKeys = true pro přeskočení neznámých polí při deserializaci, prettyPrint = true pro formátovaný výstup, coerceInputValues = true pro převod nesprávných hodnot na výchozí hodnoty. K dispozici jsou také nastavení encodeDefaults (serializace polí s výchozími hodnotami) a classDiscriminator (název pole pro polymorfní serializaci).

kotlin
// Příklad serializace a deserializace JSON
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")
    )

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

    // Deserializace z JSON
    val decoded = json.decodeFromString<Project>(jsonString)
    println(decoded.name)  // kotlinx.serialization
}

Příklad ukazuje základní cyklus serializace a deserializace. Data class Project s anotací @Serializable automaticky získá encodeToString a decodeFromString. Pole isActive má výchozí hodnotu true — pokud toto pole v JSON chybí, použije se výchozí hodnota. Pokud do JSON přijdou neznámá pole bez ignoreUnknownKeys = true, bude vyvolána výjimka SerializationException.

Polymorfní serializace sealed class

Sealed class — jeden z nejvýkonnějších případů použití kotlinx.serialization. Knihovna podporuje polymorfní serializaci pro hierarchie sealed class bez dodatečné konfigurace: stačí označit sealed class a všechny její potomky anotací @Serializable. Při serializaci se přidá pole „type” (konfigurovatelné přes classDiscriminator), na jehož základě se při deserializaci určuje konkrétní typ.

kotlin
// Polymorfní serializace sealed class
@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}")
    }
}

Polymorfní serializace sealed class je zvláště užitečná v API klientech, kde server vrací různé typy odpovědí. Bez kotlinx.serialization byste museli napsat ruční deserializátor s when podle diskriminačního pole. S knihovnou se to dělá jednou anotací. classDiscriminator umožňuje přejmenovat pole markeru (výchozí „type”) na libovolnou hodnotu očekávanou serverem.

Anotace kotlinx.serialization: úplný přehled

Knihovna poskytuje sadu anotací pro jemné ladění serializace. Hlavní je @Serializable pro třídu. Další anotace: @SerialName pro určení názvu pole v JSON (pokud se liší od názvu Kotlin), @Transient pro vyloučení pole ze serializace, @Required pro pole, které musí být v JSON přítomno, @EncodeDefault pro vynucenou serializaci pole s výchozí hodnotou.

AnotaceÚčelPříklad
@SerializableZapíná generování serializátoru pro třídu@Serializable data class User
@SerialNameUrčuje alternativní název pole ve formátu@SerialName(„user_name”) val name: String
@TransientVylučuje pole ze serializace@Transient val cache: MutableMap
@RequiredPole je povinné v JSON při deserializaci@Required val id: String
@EncodeDefaultSerializuje pole i s výchozí hodnotou@EncodeDefault val type: Type = Type.A
@SerializerPřipojuje vlastní serializátor ke třídě@Serializer(forClass = Date::class)

Anotace @SerialName je kritická při práci s API, kde jsou názvy polí v snake_case a styl Kotlin je camelCase. Například server posílá „user_id” a v kódu Kotlin se používá userId. @SerialName(„user_id”) řeší tento problém bez dalších mapperů. @Transient je užitečná pro pole, která není třeba odesílat na server — například dočasné vypočítané hodnoty nebo mezipaměť.

@Required jako alternativa k nullable polím

Ve výchozím nastavení jsou všechna pole v kotlinx.serialization povinná. Pokud pole může v JSON chybět, musíte jej učinit nullable (String?) nebo nastavit výchozí hodnotu (val name: String = „”). Existují však situace, kdy pole není nullable v Kotlin, ale může v JSON chybět kvůli verzování API. V tomto případě @SerializationException při absenci pole, zatímco výchozí hodnota vyplní default bez chyby.

Vlastní serializátory: KSerializer a ruční správa

KSerializer — rozhraní, které implementují všechny serializátory v kotlinx.serialization. Pokud standardní generování kódu není vhodné (například pro práci s Date, Bitmap nebo specifickým binárním formátem), můžete napsat vlastní serializátor. K tomu je třeba implementovat metody serialize() a deserialize() a poskytnout deskriptor — popis struktury pro schéma formátu.

Vlastní serializátory se připojují dvěma způsoby: prostřednictvím anotace @Serializable(with = MySerializer::class) pro připojení ke konkrétní třídě nebo globálně přes Json { serializersModule = ... } pro připojení ke všem instancím typu. Druhý způsob je preferován pro vestavěné typy (Date, UUID), aby se nemusela psát anotace na každém poli.

kotlin
// Vlastní serializátor pro java.util.Date
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())
    }
}

// Použití vlastního serializátoru
@Serializable
data class Event(
    val title: String,
    @Serializable(with = DateSerializer::class)
    val date: Date
)

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

V příkladu DateSerializer převádí java.util.Date na řetězec ISO 8601. Bez vlastního serializátoru kotlinx.serialization neumí pracovat s Date — to je typ, který není součástí standardní knihovny Kotlin. @Serializable(with = DateSerializer::class) na konkrétním poli připojí serializátor pouze pro toto pole. Pro globální registraci všech Date použijte Json { serializersModule = SerializersModule { contextual(DateSerializer) } }.

Formáty serializace: JSON, ProtoBuf, CBOR, HOCON

kotlinx.serialization se neomezuje pouze na JSON. Knihovna podporuje čtyři vestavěné formáty, každý s vlastním modulem a konfigurací. JSON (kotlinx-serialization-json) — univerzální, čitelný pro člověka, vhodný pro REST API. ProtoBuf (kotlinx-serialization-protobuf) — binární, kompaktní, s povinným schématem, pro vysoce zatížené mikroslužby. CBOR (kotlinx-serialization-cbor) — binární obdoba JSON, vhodná pro IoT a mobilní zařízení s omezeným provozem. HOCON (kotlinx-serialization-hocon) — konfigurační formát, kompatibilní s TypeSafe Config.

FormátModulTypSchémaTypické použití
JSONkotlinx-serialization-jsonTextovýVolitelnéREST API, ukládání dat
ProtoBufkotlinx-serialization-protobufBinárníPovinné (.proto)Mikroslužby, gRPC
CBORkotlinx-serialization-cborBinárníVolitelnéIoT, mobilní zařízení
HOCONkotlinx-serialization-hoconTextovýVolitelnéKonfigurační soubory

ProtoBuf vyžaduje definici schématu v .proto souborech, ale kotlinx-serialization-protobuf generuje Kotlin třídy přímo z @Serializable bez .proto. To zjednodušuje vývoj: stačí anotovat data class a použít ProtoBuf.encodeToByteArray(). CBOR je zvláště relevantní pro framework Android, když je třeba přenášet kompaktní binární data přes NFC nebo BLE. Velikost CBOR zprávy je v průměru o 20-30% menší než JSON při stejném souboru dat.

Výběr formátu pro projekt

Pro REST API v mobilní aplikaci je optimální JSON — ladí se bez dalších nástrojů, je čitelný v logách a kompatibilní s jakýmkoli backendem. Pokud aplikace přenáší velké objemy dat mezi mikroslužbami (stovky megabajtů) — ProtoBuf poskytne zvýšení rychlosti až 5krát díky binárnímu kódování. Pro ukládání nastavení v souborech použijte HOCON nebo JSON. Pro zařízení s přísnými omezeními provozu (IoT senzory) — CBOR.

Typické chyby při práci s kotlinx.serialization

První chyba — ignorování neznámých klíčů při deserializaci. Pokud server přidal nové pole a máte ignoreUnknownKeys = false, aplikace spadne s SerializationException. Ve výchozím nastavení je tento přepínač vypnutý. Řešení: vždy nastavte Json { ignoreUnknownKeys = true } pro produkční kód, abyste byli odolní vůči změnám API.

Druhá chyba — serializace internal nebo private polí v data class. V Kotlin data class jsou všechna pole v primárním konstruktoru ve výchozím nastavení serializována. Pokud pole obsahuje citlivá data (heslo, token), musíte jej označit @Transient nebo jej vyjmout z primárního konstruktoru. @Transient pole z JSON zcela vylučuje, ale v konstruktoru může způsobit chybu — je lepší takové pole definovat v těle třídy s @Transient.

Třetí chyba — polymorfní serializace bez sealed class. Pokud použijete open class místo sealed, kotlinx.serialization vyžaduje explicitní registraci všech potomků v serializersModule. Na rozdíl od sealed class, kde kompilátor zná všechny potomky, open class umožňuje libovolné rozšíření — knihovna nemůže automaticky určit všechny podtypy. Registrace se provádí přes Json { serializersModule = SerializersModule { polymorphic(Base::class) { subclass(Derived::class) } } }.

Chyba verzování knihovny

Verze kotlinx.serialization musí být kompatibilní s verzí Kotlin. JetBrains zveřejňuje tabulku kompatibility: kotlinx-serialization 1.6.x je kompatibilní s Kotlin 1.9.x, 1.7.x — s Kotlin 2.0.x a 2.1.x. Nesoulad verzí způsobuje záhadné chyby kompilace jako „Symbol ‘serializer’ is missing”. Vždy kontrolujte aktuální verzi na mavenCentral nebo v GitHub repozitáři projektu.

Často kladené otázky

Čím se liší kotlinx.serialization od Gson a Moshi?

kotlinx.serialization používá generování kódu v čase kompilace přes KSP, zatímco Gson a Moshi používají reflexi za běhu. To poskytuje výhodu ve výkonu (3-5krát rychlejší než Gson) a typové bezpečnosti. Gson serializuje jakékoli pole bez anotace, což může vést k úniku dat. kotlinx.serialization vyžaduje explicitní anotaci @Serializable, což je bezpečnější. Moshi také podporuje codegen, ale pouze pro JVM a Android.

Podporuje kotlinx.serialization Kotlin Multiplatform?

Ano, kotlinx.serialization je oficiální multiplatformní knihovna JetBrains. Funguje na Kotlin/JVM (Android, Backend), Kotlin/Native (iOS), Kotlin/JS (Web, React) a Kotlin/Wasm. API je jednotné pro všechny platformy: @Serializable + Json.encodeToString() funguje všude stejně. Pro iOS nejsou vyžadována žádná další nastavení — Kotlin/Native zkompiluje serializovaný kód do nativního binárního souboru.

Jak zpracovat null pole v JSON?

Nullable pole (String?) se deserializují jako null, pokud hodnota v JSON chybí nebo je uvedena jako null. Pro non-nullable pole (String) bez výchozí hodnoty způsobí absence pole v JSON SerializationException. Pokud chcete, aby null hodnoty nevstupovaly do JSON, nakonfigurujte Json { encodeDefaults = false }. To vyloučí z výstupu všechna pole rovna default (včetně null pro nullable).

Co dělat, když server posílá pole v snake_case?

Použijte @SerialName(„snake_case_name”) na každém poli, jehož název se liší od formátu Kotlin. Alternativně je pro Kotlin 2.0+ k dispozici Json { namingStrategy = JsonNamingStrategy.SnakeCase } — automatická konverze camelCase ↔ snake_case. Toto nastavení se aplikuje na všechna pole najednou. Pokud je vyžadováno částečné přizpůsobení, kombinujte @SerialName s globální strategií.

Lze serializovat Kotlin Flow nebo coroutine?

Ne, Flow a corutiny nejsou přímo serializovatelné — představují asynchronní provádění, nikoli data. Pro přenos dat z Flow je musíte shromáždit do kolekce pomocí .toList() v corutině a serializovat kolekci. Podobně nelze serializovat Job, Deferred nebo Continuation. Serializujte pouze data class — datové modely bez behaviorální logiky.

Shrnutí

  • kotlinx.serialization — serializace v čase kompilace přes @Serializable, bez reflexe, s výkonem až 5krát vyšším než Gson
  • @Serializable, @SerialName, @Transient — klíčové anotace pro konfiguraci serializace polí a tříd
  • Json {} builder konfiguruje JSON: ignoreUnknownKeys, prettyPrint, coerceInputValues, encodeDefaults
  • Sealed class a polymorfní serializace — bezproblémová podpora typových hierarchií bez dodatečného kódu
  • KSerializer — rozhraní pro vlastní serializátory nestandardních typů (Date, Bitmap, UUID)
  • Čtyři formáty: JSON, ProtoBuf, CBOR, HOCON — připojují se moduly, API jednotné pro všechny
  • Multiplatformnost — jednotný kód pro JVM, Native, JS a Wasm; kritické pro KMM a sdílené moduly

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také