Moshi è una libreria JSON moderna di Square, creata specificamente per Kotlin e Android tenendo conto dei limiti di Gson. È completamente compatibile con la sicurezza nulla di Kotlin, genera codice in fase di compilazione e non utilizza la riflessione, migliorando le prestazioni e l'affidabilità. Secondo Square Moshi, 2024, Moshi fornisce una serializzazione prevedibile e supporta adattatori personalizzati per qualsiasi tipo di dato.
Punti chiave
Moshi è una libreria JSON per JVM, Android e Kotlin Multiplatform, creata da Square (gli autori di OkHttp e Retrofit). A differenza di Gson, Moshi non si basa sulla riflessione — gli adattatori vengono generati in fase di compilazione tramite l'annotazione @JsonClass(generateAdapter = true). Ciò rende Moshi più veloce, sicura e prevedibile quando si lavora con costrutti specifici di Kotlin.
La differenza principale tra Moshi e i suoi predecessori è il rifiuto della riflessione. La riflessione consente a Gson di funzionare con qualsiasi classe senza preparazione, ma il costo è un'inizializzazione lenta, l'impossibilità di ottimizzazione da parte del compilatore e il rischio di errori in fase di esecuzione. Moshi richiede una dichiarazione esplicita delle classi per la generazione del codice, ma in cambio offre la velocità del codice scritto a mano e la piena sicurezza dei tipi in fase di compilazione.
// Aggiungere Moshi a 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"
}
// Modello semplice con generazione di codice
@JsonClass(generateAdapter = true)
data class User(
@Json(name = "user_id")
val id: Int,
val name: String,
val email: String,
val avatar: String? = null
)
// Utilizzo
val moshi = Moshi.Builder()
.build()
val jsonAdapter = moshi.adapter(User::class.java)
Per iniziare a lavorare con Moshi, è necessario aggiungere dipendenze al build.gradle e annotare i modelli. Moshi.Builder funge da punto di ingresso: attraverso di esso vengono aggiunti adattatori integrati per i tipi standard, adattatori personalizzati e configurato il comportamento della libreria. Moshi supporta adattatori per Date, Enum, Collection e Map nativamente, ma le classi Kotlin richiedono il modulo moshi-kotlin. A differenza di Gson, Moshi non utilizza la riflessione per le classi Kotlin per impostazione predefinita — per questo viene collegato KotlinJsonAdapterFactory, che funge da fallback quando la generazione del codice non viene utilizzata o la classe non è annotata con @JsonClass. Questo approccio garantisce che lo sviluppatore scelga esplicitamente tra le prestazioni della generazione del codice e la flessibilità della riflessione per ogni classe specifica.
Dopo aver costruito Moshi tramite Builder, lo sviluppatore ottiene un'istanza di Moshi e richiede un adattatore per la classe desiderata. JsonAdapter è l'oggetto centrale che esegue la serializzazione tramite toJson() e la deserializzazione tramite fromJson(). Moshi utilizza automaticamente l'adattatore generato se la classe è annotata con @JsonClass(generateAdapter = true), altrimenti applica il KotlinJsonAdapterFactory riflessivo come fallback. Questo approccio combina la velocità della generazione del codice con la flessibilità di un meccanismo riflessivo per progetti di qualsiasi scala e complessità. Moshi è adatto sia per piccole applicazioni che per grandi progetti aziendali con centinaia di modelli di dati.
// Configurare Moshi con KotlinJsonAdapterFactory
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.add(LocalDateAdapter())
.build()
// Usare l'adattatore
val adapter = moshi.adapter(User::class.java)
// Serializzazione
val user = User(1, "Alice", "alice@test.com")
val json = adapter.toJson(user)
// Deserializzazione
val jsonString = """{"user_id":2,"name":"Bob","email":"bob@test.com"}"""
val parsedUser = adapter.fromJson(jsonString)
// Lavorare con le liste
val listAdapter = moshi.adapter(
Types.newParameterizedType(
List::class.java,
User::class.java
)
)
Moshi utilizza annotazioni per configurare la serializzazione e supportare tipi personalizzati. @Json(name = "...") imposta la chiave JSON per un campo. @Transient esclude un campo dalla serializzazione. @JsonClass(generateAdapter = true) abilita la generazione del codice. Per la logica personalizzata, Moshi fornisce le annotazioni @ToJson e @FromJson, che possono essere posizionate in una classe adattatrice separata.
L'annotazione @Json sostituisce @SerializedName di Gson e funziona in modo simile: il campo kotlinName viene associato alla chiave JSON "kotlin_name". Per i tipi che Moshi non può serializzare per impostazione predefinita (ad esempio LocalDate), lo sviluppatore crea una classe con metodi @ToJson e @FromJson. Gli adattatori vengono registrati tramite Moshi.Builder.add() e si applicano globalmente o a un tipo specifico. Moshi supporta classi sealed e serializzazione polimorfica tramite @JsonClass con un discriminatore esplicito, consentendo di lavorare con gerarchie di tipi in JSON senza controllo manuale dei campi. Durante la deserializzazione, Moshi ignora per impostazione predefinita le chiavi JSON sconosciute, garantendo la compatibilità all'indietro quando si aggiungono nuovi campi lato server senza modificare il codice client. Per il debug, è possibile attivare la modalità rigorosa tramite failOnUnknown, che genera un'eccezione quando vengono trovate chiavi sconosciute.
// Adattatore personalizzato per 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)
}
}
// Modello con annotazioni 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
)
// Registrare l'adattatore
val moshi = Moshi.Builder()
.add(LocalDateAdapter())
.add(KotlinJsonAdapterFactory())
.build()
Confrontare Moshi e Gson è una domanda comune quando si sceglie una libreria JSON per un progetto Android. Moshi vince nello sviluppo moderno con Kotlin grazie alla generazione del codice, alla sicurezza nulla e alla velocità. Gson rimane rilevante per progetti Java, codice legacy e scenari in cui la configurazione minima è importante. La differenza diventa evidente con grandi volumi di dati e modelli complessi.
I test delle prestazioni mostrano che Moshi con generazione di codice è 2–5 volte più veloce di Gson nelle operazioni di serializzazione e deserializzazione. Il vantaggio principale di Moshi è la corretta gestione della sicurezza nulla di Kotlin: se un campo è assente in JSON e il modello lo dichiara come non nullo senza valore predefinito, Moshi genera un'eccezione al momento della deserializzazione, prevenendo errori nascosti.
| Caratteristica | Gson | Moshi |
|---|---|---|
| Meccanismo | riflessione | generazione codice / riflessione |
| sicurezza nulla | non considera | pieno supporto Kotlin |
| Velocità | media | alta |
| Valori predefiniti | non supporta | supporta |
| Kotlin Multiplatform | no | sì |
| Dimensione libreria | ~240 Kb | ~150 Kb |
La scelta tra Moshi e Gson dipende dal contesto del progetto. I nuovi progetti in Kotlin traggono vantaggio da Moshi grazie alla sicurezza dei tipi e alle prestazioni. Gson rimane una scelta ragionevole per supportare codice Java, strutture JSON dinamiche o quando la semplicità di configurazione è più importante della velocità. Per Kotlin Multiplatform, Moshi è l'unica delle due opzioni che supporta questa piattaforma.
Durante la migrazione da Gson a Moshi, le modifiche principali riguardano annotazioni e adattatori. @SerializedName di Gson viene sostituito con @Json(name = "..."), e JsonSerializer/JsonDeserializer personalizzati con la coppia @ToJson/@FromJson. Per i modelli con valori predefiniti e campi nullable, Moshi si comporta in modo più prevedibile: se un campo non nullo senza valore predefinito è assente in JSON, Moshi genera JsonDataException, prevenendo NPE nascosti. L'integrazione con Retrofit tramite MoshiConverterFactory viene aggiunta con una singola dipendenza e non richiede la modifica dell'architettura del livello di rete. Per l'offuscamento tramite ProGuard o R8, è necessario aggiungere regole per preservare le classi annotate con @JsonClass e gli adattatori generati, altrimenti la serializzazione si romperà nella build di rilascio. Nel complesso, la migrazione da Gson a Moshi è giustificata nei nuovi progetti Kotlin dove prestazioni e sicurezza dei tipi sono importanti.
// Confronto serializzazione: Gson vs Moshi
data class Sample(
val name: String,
val count: Int,
val tags: List<String> = listOf()
)
// Gson: funziona tramite riflessione
val gson = Gson()
val fromGson = gson.fromJson("""{"name":"test"}""",
Sample::class.java)
// count = 0 (predefinito), ma la sicurezza nulla non viene verificata
// Moshi: richiede un adattatore, la sicurezza nulla è esplicita
@JsonClass(generateAdapter = true)
data class SampleMoshi(
val name: String,
val count: Int,
val tags: List<String> = listOf()
)
Domande frequenti
Moshi è una libreria JSON di Square per Kotlin e Android che utilizza la generazione di codice invece della riflessione. Fornisce prestazioni elevate, corretta gestione della sicurezza nulla di Kotlin e compatibilità con Kotlin Multiplatform.
Moshi supera Gson in velocità (2–5 volte più veloce grazie alla generazione di codice), sicurezza (rispetta le annotazioni nulle di Kotlin) e dimensione (~90 Kb più piccolo). Moshi supporta anche Kotlin Multiplatform e i valori predefiniti in data class.
@JsonClass(generateAdapter = true) indica a Moshi di generare un adattatore per la classe specificata in fase di compilazione. L'adattatore generato esegue la serializzazione direttamente, senza riflessione, offrendo le massime prestazioni.
Crea una classe con metodi annotati con @ToJson (serializzazione) e @FromJson (deserializzazione). Registra l'istanza tramite Moshi.Builder.add(). Moshi troverà e applicherà automaticamente l'adattatore quando lavora con il tipo corrispondente.
Sì, Moshi supporta Kotlin Multiplatform a partire dalla versione 1.13.0. Ciò lo rende l'unica soluzione JSON popolare per progetti KMP, consentendo di utilizzare codice di serializzazione comune su tutte le piattaforme target.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche