Moshi je moderní JSON knihovna od Square, vytvořená speciálně pro Kotlin a Android s ohledem na omezení Gson. Je plně kompatibilní s null-bezpečností Kotlin, generuje kód ve fázi kompilace a nepoužívá reflexi, což zvyšuje výkon a spolehlivost. Podle údajů Square Moshi, 2024, Moshi poskytuje předvídatelnou serializaci a podporuje vlastní adaptéry pro všechny typy dat.
Hlavní body
Moshi je JSON knihovna pro JVM, Android a Kotlin Multiplatform, vytvořená společností Square (autory OkHttp a Retrofit). Na rozdíl od Gson, Moshi nespoléhá na reflexi — adaptéry jsou generovány ve fázi kompilace pomocí anotace @JsonClass(generateAdapter = true). Díky tomu je Moshi rychlejší, bezpečnější a předvídatelnější při práci s konstrukcemi specifickými pro Kotlin.
Hlavním rozdílem Moshi oproti předchůdcům je opuštění reflexe. Reflexe umožňuje Gson pracovat s jakoukoli třídou bez přípravy, ale za cenu pomalé inicializace, nemožnosti optimalizace kompilátorem a rizika chyb za běhu. Moshi vyžaduje explicitní uvedení tříd pro generování kódu, ale na oplátku poskytuje rychlost ručně psaného kódu a úplnou typovou bezpečnost ve fázi kompilace.
// Připojení Moshi v build.gradle
dependencies {
implementation "com.squareup.moshi:moshi:1.15.0"
implementation "com.squareup.moshi:moshi-kotlin:1.15.0"
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.15.0"
}
// Jednoduchý model s generováním kódu
@JsonClass(generateAdapter = true)
data class User(
@Json(name = "user_id")
val id: Int,
val name: String,
val email: String,
val avatar: String? = null
)
// Použití
val moshi = Moshi.Builder()
.build()
val jsonAdapter = moshi.adapter(User::class.java)
Pro zahájení práce s Moshi je třeba přidat závislosti v build.gradle a anotovat modely. Moshi.Builder slouží jako vstupní bod: prostřednictvím něj se přidávají vestavěné adaptéry pro standardní typy, vlastní adaptéry a konfiguruje se chování knihovny. Moshi podporuje adaptéry pro Date, Enum, Collection a Map hned po vybalení, ale pro třídy Kotlin je vyžadován modul moshi-kotlin. Na rozdíl od Gson, Moshi standardně nepoužívá reflexi pro třídy Kotlin — k tomu se připojuje KotlinJsonAdapterFactory, který slouží jako záložní volba, když se negeneruje kód nebo třída není anotována @JsonClass. Tento přístup zaručuje, že vývojář explicitně volí mezi výkonem generování kódu a flexibilitou reflexe pro každou konkrétní třídu.
Po sestavení Moshi pomocí Builderu získá vývojář instanci Moshi a požádá o adaptér pro požadovanou třídu. JsonAdapter je centrální objekt, který provádí serializaci pomocí toJson() a deserializaci pomocí fromJson(). Moshi automaticky používá vygenerovaný adaptér, pokud je třída anotována @JsonClass(generateAdapter = true), jinak použije reflexivní KotlinJsonAdapterFactory jako záložní volbu. Tento přístup kombinuje rychlost generování kódu s flexibilitou reflexivního mechanismu pro projekty jakékoli velikosti a úrovně složitosti. Moshi je vhodný jak pro malé aplikace, tak pro velké korporátní projekty se stovkami datových modelů.
// Konfigurace Moshi s KotlinJsonAdapterFactory
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.add(LocalDateAdapter())
.build()
// Použití adaptéru
val adapter = moshi.adapter(User::class.java)
// Serializace
val user = User(1, "Alice", "alice@test.com")
val json = adapter.toJson(user)
// Deserializace
val jsonString = """{"user_id":2,"name":"Bob","email":"bob@test.com"}"""
val parsedUser = adapter.fromJson(jsonString)
// Práce se seznamem
val listAdapter = moshi.adapter(
Types.newParameterizedType(
List::class.java,
User::class.java
)
)
Moshi používá anotace pro konfiguraci serializace a podporu vlastních typů. @Json(name = "...") nastavuje JSON klíč pro pole. @Transient vylučuje pole ze serializace. @JsonClass(generateAdapter = true) zapíná generování kódu. Pro vlastní logiku Moshi poskytuje anotace @ToJson a @FromJson, které lze umístit do samostatné třídy adaptéru.
Anotace @Json nahrazuje Gsonovský @SerializedName a funguje podobně: pole kotlinName je propojeno s JSON klíčem „kotlin_name“. Pro typy, které Moshi nedokáže serializovat standardně (např. LocalDate), vytvoří vývojář třídu s metodami @ToJson a @FromJson. Adaptéry se registrují pomocí Moshi.Builder.add() a aplikují se globálně nebo na konkrétní typ. Moshi podporuje sealed class a polymorfní serializaci pomocí @JsonClass s explicitním uvedením diskriminátoru, což umožňuje práci s hierarchiemi typů v JSON bez ruční kontroly polí. Při deserializaci Moshi standardně ignoruje neznámé klíče v JSON, což zajišťuje zpětnou kompatibilitu při přidávání nových polí na straně serveru bez změny kódu klienta. Pro ladění lze zapnout přísný režim pomocí failOnUnknown, který vyvolá výjimku při detekci neznámých klíčů.
// Vlastní adaptér pro LocalDate
class LocalDateAdapter {
@ToJson
fun toJson(date: LocalDate): String {
return date.format(DateTimeFormatter.ISO_LOCAL_DATE)
}
@FromJson
fun fromJson(dateString: String): LocalDate {
return LocalDate.parse(dateString)
}
}
// Model s anotacemi Moshi
@JsonClass(generateAdapter = true)
data class Event(
@Json(name = "event_id")
val id: Int,
@Json(name = "event_date")
val date: LocalDate,
@Transient
val localCache: String? = null
)
// Registrace adaptéru
val moshi = Moshi.Builder()
.add(LocalDateAdapter())
.add(KotlinJsonAdapterFactory())
.build()
Srovnání Moshi a Gson je častá otázka při výběru JSON knihovny pro Android projekt. Moshi vítězí v moderním vývoji Kotlin díky generování kódu, null-bezpečnosti a rychlosti. Gson zůstává relevantní pro Java projekty, legacy kód a scénáře, kde je důležitá minimální konfigurace. Rozdíl je patrný při velkých objemech dat a složitých modelech.
Výkonnostní testy ukazují, že Moshi s generováním kódu pracuje 2-5krát rychleji než Gson při serializaci a deserializaci. Klíčovou výhodou Moshi je správné zpracování null-bezpečnosti Kotlin: pokud pole chybí v JSON a v modelu je deklarováno jako non-null bez výchozí hodnoty, Moshi vyvolá výjimku ve fázi deserializace, čímž předchází skrytým chybám.
| Vlastnost | Gson | Moshi |
|---|---|---|
| Mechanismus | reflexe | generování kódu / reflexe |
| Null safety | nebere v úvahu | plná podpora Kotlin |
| Rychlost | střední | vysoká |
| Výchozí hodnoty | nepodporuje | podporuje |
| Kotlin Multiplatform | ne | ano |
| Velikost knihovny | ~240 Kb | ~150 Kb |
Volba mezi Moshi a Gson závisí na kontextu projektu. Nové projekty na Kotlin těží z Moshi díky typové bezpečnosti a výkonu. Gson zůstává rozumnou volbou pro podporu Java kódu, dynamických JSON struktur nebo když je jednoduchost připojení důležitější než rychlost. Pro Kotlin Multiplatform je Moshi jediným z obou variant, který tuto platformu podporuje.
Při migraci z Gson na Moshi se hlavní změny týkají anotací a adaptérů. Gsonovský @SerializedName se nahrazuje @Json(name = "...") a vlastní JsonSerializer/JsonDeserializer — dvojicí @ToJson/@FromJson. Pro modely s výchozími hodnotami a nullable poli se Moshi chová předvídatelněji: pokud v JSON chybí non-null pole bez výchozí hodnoty, Moshi vyvolá JsonDataException, čímž předchází skrytým NPE. Integrace s Retrofit přes MoshiConverterFactory se přidá jednou závislostí a nevyžaduje změnu architektury síťové vrstvy. Pro obfuskaci přes ProGuard nebo R8 je třeba přidat pravidla pro zachování tříd anotovaných @JsonClass a generovaných adaptérů, jinak se serializace rozbije v release verzi. Celkově je migrace z Gson na Moshi opodstatněná v nových Kotlin projektech, kde je důležitý výkon a typová bezpečnost.
// Porovnání serializace: Gson vs Moshi
data class Sample(
val name: String,
val count: Int,
val tags: List<String> = listOf()
)
// Gson: funguje přes reflexi
val gson = Gson()
val fromGson = gson.fromJson("""{"name":"test"}""",
Sample::class.java)
// count = 0 (default), ale null-bezpečnost není kontrolována
// Moshi: vyžaduje adaptér, null-bezpečnost je explicitní
@JsonClass(generateAdapter = true)
data class SampleMoshi(
val name: String,
val count: Int,
val tags: List<String> = listOf()
)
Často kladené otázky
Moshi je JSON knihovna od Square pro Kotlin a Android, která používá generování kódu místo reflexe. Poskytuje vysoký výkon, správné zpracování null-bezpečnosti Kotlin a kompatibilitu s Kotlin Multiplatform.
Moshi překonává Gson v rychlosti (2-5krát rychlejší díky generování kódu), bezpečnosti (bere v úvahu null anotace Kotlin) a velikosti (o ~90 Kb menší). Moshi také podporuje Kotlin Multiplatform a výchozí hodnoty v data class.
@JsonClass(generateAdapter = true) přikazuje Moshi vygenerovat adaptér pro tuto třídu ve fázi kompilace. Vygenerovaný adaptér provádí serializaci přímo, bez reflexe, což poskytuje maximální výkon.
Vytvořte třídu s metodami anotovanými @ToJson (serializace) a @FromJson (deserializace). Zaregistrujte instanci pomocí Moshi.Builder.add(). Moshi automaticky najde a použije adaptér při práci s odpovídajícím typem.
Ano, Moshi podporuje Kotlin Multiplatform od verze 1.13.0. To z něj dělá jediné populární JSON řešení pro KMP projekty, umožňující použití společného serializačního kódu na všech cílových platformách.
Shrnutí
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í.
Přečtěte si také