Moshi är ett modernt JSON-bibliotek från Square, skapat speciellt för Kotlin och Android med hänsyn till Gsons begränsningar. Det är fullt kompatibelt med Kotlins null-säkerhet, genererar kod i kompileringsfasen och använder inte reflektion, vilket ökar prestanda och tillförlitlighet. Enligt uppgifter från Square Moshi, 2024, Moshi ger förutsägbar serialisering och stöder anpassade adaptrar för alla datatyper.
Huvudpunkter
Moshi är ett JSON-bibliotek för JVM, Android och Kotlin Multiplatform, skapat av Square (skaparna av OkHttp och Retrofit). Till skillnad från Gson förlitar sig Moshi inte på reflektion — adaptrar genereras i kompileringsfasen via anteckningen @JsonClass(generateAdapter = true). Detta gör Moshi snabbare, säkrare och mer förutsägbart vid arbete med Kotlin-specifika konstruktioner.
Den huvudsakliga skillnaden mellan Moshi och dess föregångare är avståendet från reflektion. Reflektion tillåter Gson att arbeta med vilken klass som helst utan förberedelse, men till priset av långsam initiering, omöjlighet till optimering av kompilatorn och risk för fel under körning. Moshi kräver explicit angivelse av klasser för kodgenerering, men ger i gengäld hastigheten hos handskriven kod och fullständig typsäkerhet i kompileringsfasen.
// Ansluta Moshi i 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"
}
// Enkel modell med kodgenerering
@JsonClass(generateAdapter = true)
data class User(
@Json(name = "user_id")
val id: Int,
val name: String,
val email: String,
val avatar: String? = null
)
// Användning
val moshi = Moshi.Builder()
.build()
val jsonAdapter = moshi.adapter(User::class.java)
För att börja arbeta med Moshi måste beroenden läggas till i build.gradle och modeller antecknas. Moshi.Builder fungerar som startpunkt: genom det läggs inbyggda adaptrar för standardtyper, anpassade adaptrar till och bibliotekets beteende konfigureras. Moshi stöder adaptrar för Date, Enum, Collection och Map direkt, men för Kotlin-klasser krävs modulen moshi-kotlin. Till skillnad från Gson använder Moshi som standard inte reflektion för Kotlin-klasser — för detta ansluts KotlinJsonAdapterFactory, som fungerar som reservalternativ när kodgenerering inte tillämpas eller klassen inte är antecknad med @JsonClass. Detta tillvägagångssätt garanterar att utvecklaren explicit väljer mellan prestandan hos kodgenerering och flexibiliteten hos reflektion för varje specifik klass.
Efter att ha byggt Moshi via Builder får utvecklaren en Moshi-instans och begär en adapter för önskad klass. JsonAdapter är det centrala objektet som utför serialisering via toJson() och deserialisering via fromJson(). Moshi använder automatiskt den genererade adaptern om klassen är antecknad med @JsonClass(generateAdapter = true), annars tillämpar den reflektiva KotlinJsonAdapterFactory som reservalternativ. Denna metod kombinerar hastigheten hos kodgenerering med flexibiliteten hos den reflektiva mekanismen för projekt av alla storlekar och komplexitetsnivåer. Moshi passar både för små applikationer och stora företagsprojekt med hundratals datamodeller.
// Konfigurera Moshi med KotlinJsonAdapterFactory
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.add(LocalDateAdapter())
.build()
// Använda adapter
val adapter = moshi.adapter(User::class.java)
// Serialisering
val user = User(1, "Alice", "alice@test.com")
val json = adapter.toJson(user)
// Deserialisering
val jsonString = """{"user_id":2,"name":"Bob","email":"bob@test.com"}"""
val parsedUser = adapter.fromJson(jsonString)
// Arbeta med lista
val listAdapter = moshi.adapter(
Types.newParameterizedType(
List::class.java,
User::class.java
)
)
Moshi använder anteckningar för att konfigurera serialisering och stödja anpassade typer. @Json(name = "...") ställer in JSON-nyckeln för ett fält. @Transient utesluter ett fält från serialisering. @JsonClass(generateAdapter = true) aktiverar kodgenerering. För anpassad logik tillhandahåller Moshi anteckningarna @ToJson och @FromJson, som kan placeras i en separat adapterklass.
Anteckningen @Json ersätter Gsons @SerializedName och fungerar liknande: fältet kotlinName kopplas till JSON-nyckeln “kotlin_name”. För typer som Moshi inte kan serialisera som standard (t.ex. LocalDate) skapar utvecklaren en klass med metoder @ToJson och @FromJson. Adaptrar registreras via Moshi.Builder.add() och tillämpas globalt eller för en specifik typ. Moshi stöder sealed class och polymorf serialisering via @JsonClass med explicit angivelse av diskriminator, vilket möjliggör arbete med typhierarkier i JSON utan manuell fältkontroll. Vid deserialisering ignorerar Moshi som standard okända nycklar i JSON, vilket säkerställer bakåtkompatibilitet vid tillägg av nya fält på serversidan utan ändring av klientkoden. För felsökning kan strikt läge aktiveras via failOnUnknown, som kastar ett undantag vid upptäckt av okända nycklar.
// Anpassad adapter för 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)
}
}
// Modell med Moshi-anteckningar
@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
)
// Registrera adapter
val moshi = Moshi.Builder()
.add(LocalDateAdapter())
.add(KotlinJsonAdapterFactory())
.build()
Jämförelse mellan Moshi och Gson är en vanlig fråga vid val av JSON-bibliotek för ett Android-projekt. Moshi vinner i modern Kotlin-utveckling tack vare kodgenerering, null-säkerhet och hastighet. Gson förblir relevant för Java-projekt, äldre kod och scenarier där minimal konfiguration är viktig. Skillnaden blir märkbar vid stora datamängder och komplexa modeller.
Prestandatester visar att Moshi med kodgenerering fungerar 2-5 gånger snabbare än Gson vid serialiserings- och deserialiseringsoperationer. Den viktigaste fördelen med Moshi är korrekt hantering av Kotlins null-säkerhet: om ett fält saknas i JSON och i modellen deklareras som non-null utan standardvärde, kastar Moshi ett undantag i deserialiseringsfasen, vilket förhindrar dolda fel.
| Egenskap | Gson | Moshi |
|---|---|---|
| Mekanism | reflektion | kodgenerering / reflektion |
| Null safety | tar inte hänsyn | fullt Kotlin-stöd |
| Hastighet | medel | hög |
| Standardvärden | stöder inte | stöder |
| Kotlin Multiplatform | nej | ja |
| Biblioteksstorlek | ~240 Kb | ~150 Kb |
Valet mellan Moshi och Gson beror på projektets sammanhang. Nya projekt på Kotlin drar nytta av Moshi tack vare typsäkerhet och prestanda. Gson förblir ett rimligt val för stöd av Java-kod, dynamiska JSON-strukturer eller när anslutningsenkelhet är viktigare än hastighet. För Kotlin Multiplatform är Moshi den enda av de två varianterna som stöder denna plattform.
Vid migrering från Gson till Moshi rör de viktigaste ändringarna anteckningar och adaptrar. Gsons @SerializedName ersätts med @Json(name = "...") och anpassade JsonSerializer/JsonDeserializer — med paret @ToJson/@FromJson. För modeller med standardvärden och nullable fält beter sig Moshi mer förutsägbart: om ett non-null fält utan standardvärde saknas i JSON kastar Moshi JsonDataException, vilket förhindrar dolda NPE. Integration med Retrofit via MoshiConverterFactory läggs till med ett beroende och kräver ingen ändring av nätverkslagrets arkitektur. För obfuskering via ProGuard eller R8 måste regler läggas till för att bevara @JsonClass-antecknade klasser och genererade adaptrar, annars kommer serialiseringen att brytas i release-bygget. Sammantaget är migrering från Gson till Moshi motiverad i nya Kotlin-projekt där prestanda och typsäkerhet är viktiga.
// Jämförelse av serialisering: Gson vs Moshi
data class Sample(
val name: String,
val count: Int,
val tags: List<String> = listOf()
)
// Gson: fungerar via reflektion
val gson = Gson()
val fromGson = gson.fromJson("""{"name":"test"}""",
Sample::class.java)
// count = 0 (default), men null-säkerhet kontrolleras inte
// Moshi: kräver adapter, null-säkerhet är explicit
@JsonClass(generateAdapter = true)
data class SampleMoshi(
val name: String,
val count: Int,
val tags: List<String> = listOf()
)
Vanliga frågor
Moshi är ett JSON-bibliotek från Square för Kotlin och Android som använder kodgenerering istället för reflektion. Det ger hög prestanda, korrekt hantering av Kotlins null-säkerhet och kompatibilitet med Kotlin Multiplatform.
Moshi överträffar Gson i hastighet (2-5 gånger snabbare tack vare kodgenerering), säkerhet (tar hänsyn till Kotlins null-anteckningar) och storlek (~90 Kb mindre). Moshi stöder även Kotlin Multiplatform och standardvärden i data class.
@JsonClass(generateAdapter = true) instruerar Moshi att generera en adapter för denna klass i kompileringsfasen. Den genererade adaptern utför serialisering direkt, utan reflektion, vilket ger maximal prestanda.
Skapa en klass med metoder antecknade med @ToJson (serialisering) och @FromJson (deserialisering). Registrera instansen via Moshi.Builder.add(). Moshi kommer automatiskt att hitta och tillämpa adaptern vid arbete med motsvarande typ.
Ja, Moshi stöder Kotlin Multiplatform från version 1.13.0. Detta gör det till den enda populära JSON-lösningen för KMP-projekt, vilket möjliggör användning av gemensam serialiseringskod på alla målplattformar.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också