Moshi est une bibliothèque JSON moderne de Square, créée spécifiquement pour Kotlin et Android en tenant compte des limites de Gson. Elle est entièrement compatible avec la sécurité nulle de Kotlin, génère du code à la compilation et n’utilise pas la réflexion, ce qui améliore les performances et la fiabilité. Selon Square Moshi, 2024, Moshi assure une sérialisation prévisible et prend en charge des adaptateurs personnalisés pour tout type de données.
Points clés
Moshi est une bibliothèque JSON pour JVM, Android et Kotlin Multiplatform, créée par Square (les auteurs d’OkHttp et Retrofit). Contrairement à Gson, Moshi ne repose pas sur la réflexion — les adaptateurs sont générés à la compilation via l’annotation @JsonClass(generateAdapter = true). Cela rend Moshi plus rapide, plus sûr et plus prévisible lors du travail avec des constructions spécifiques à Kotlin.
La principale différence entre Moshi et ses prédécesseurs est le rejet de la réflexion. La réflexion permet à Gson de fonctionner avec n’importe quelle classe sans préparation, mais le coût en est une initialisation lente, l’impossibilité d’optimisation par le compilateur et le risque d’erreurs à l’exécution. Moshi nécessite une déclaration explicite des classes pour la génération de code, mais en échange offre la vitesse du code écrit à la main et une sécurité de type complète à la compilation.
// Ajouter Moshi au 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"
}
// Modèle simple avec génération de code
@JsonClass(generateAdapter = true)
data class User(
@Json(name = "user_id")
val id: Int,
val name: String,
val email: String,
val avatar: String? = null
)
// Utilisation
val moshi = Moshi.Builder()
.build()
val jsonAdapter = moshi.adapter(User::class.java)
Pour commencer à travailler avec Moshi, vous devez ajouter des dépendances au build.gradle et annoter les modèles. Moshi.Builder sert de point d’entrée : à travers lui, des adaptateurs intégrés pour les types standard, des adaptateurs personnalisés sont ajoutés et le comportement de la bibliothèque est configuré. Moshi prend en charge les adaptateurs pour Date, Enum, Collection et Map nativement, mais les classes Kotlin nécessitent le module moshi-kotlin. Contrairement à Gson, Moshi n’utilise pas la réflexion pour les classes Kotlin par défaut — pour cela, KotlinJsonAdapterFactory est connecté, servant de solution de repli lorsque la génération de code n’est pas utilisée ou que la classe n’est pas annotée avec @JsonClass. Cette approche garantit que le développeur choisit explicitement entre les performances de la génération de code et la flexibilité de la réflexion pour chaque classe spécifique.
Après avoir construit Moshi via Builder, le développeur obtient une instance de Moshi et demande un adaptateur pour la classe souhaitée. JsonAdapter est l’objet central qui effectue la sérialisation via toJson() et la désérialisation via fromJson(). Moshi utilise automatiquement l’adaptateur généré si la classe est annotée avec @JsonClass(generateAdapter = true), sinon il applique le KotlinJsonAdapterFactory réflexif comme solution de repli. Cette approche combine la vitesse de la génération de code avec la flexibilité d’un mécanisme réflexif pour des projets de toute taille et complexité. Moshi convient aussi bien aux petites applications qu’aux grands projets d’entreprise avec des centaines de modèles de données.
// Configurer Moshi avec KotlinJsonAdapterFactory
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.add(LocalDateAdapter())
.build()
// Utiliser l’adaptateur
val adapter = moshi.adapter(User::class.java)
// Sérialisation
val user = User(1, "Alice", "alice@test.com")
val json = adapter.toJson(user)
// Désérialisation
val jsonString = """{"user_id":2,"name":"Bob","email":"bob@test.com"}"""
val parsedUser = adapter.fromJson(jsonString)
// Travailler avec des listes
val listAdapter = moshi.adapter(
Types.newParameterizedType(
List::class.java,
User::class.java
)
)
Moshi utilise des annotations pour configurer la sérialisation et prendre en charge les types personnalisés. @Json(name = "...") définit la clé JSON d’un champ. @Transient exclut un champ de la sérialisation. @JsonClass(generateAdapter = true) active la génération de code. Pour la logique personnalisée, Moshi fournit les annotations @ToJson et @FromJson, qui peuvent être placées dans une classe d’adaptateur séparée.
L’annotation @Json remplace @SerializedName de Gson et fonctionne de manière similaire : le champ kotlinName est associé à la clé JSON « kotlin_name ». Pour les types que Moshi ne peut pas sérialiser par défaut (par exemple, LocalDate), le développeur crée une classe avec des méthodes @ToJson et @FromJson. Les adaptateurs sont enregistrés via Moshi.Builder.add() et s’appliquent globalement ou à un type spécifique. Moshi prend en charge les classes sealed et la sérialisation polymorphe via @JsonClass avec un discriminateur explicite, permettant de travailler avec des hiérarchies de types en JSON sans vérification manuelle des champs. Lors de la désérialisation, Moshi ignore par défaut les clés JSON inconnues, garantissant la rétrocompatibilité lors de l’ajout de nouveaux champs côté serveur sans modifier le code client. Pour le débogage, le mode strict peut être activé via failOnUnknown, qui lève une exception lorsque des clés inconnues sont trouvées.
// Adaptateur personnalisé pour 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)
}
}
// Modèle avec annotations 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
)
// Enregistrer l’adaptateur
val moshi = Moshi.Builder()
.add(LocalDateAdapter())
.add(KotlinJsonAdapterFactory())
.build()
Comparer Moshi et Gson est une question fréquente lors du choix d’une bibliothèque JSON pour un projet Android. Moshi l’emporte dans le développement moderne avec Kotlin grâce à la génération de code, à la sécurité nulle et à la vitesse. Gson reste pertinent pour les projets Java, le code existant et les scénarios où une configuration minimale est importante. La différence devient perceptible avec de grands volumes de données et des modèles complexes.
Les tests de performance montrent que Moshi avec génération de code est 2 à 5 fois plus rapide que Gson pour les opérations de sérialisation et désérialisation. L’avantage clé de Moshi est le traitement correct de la sécurité nulle de Kotlin : si un champ est absent du JSON et que le modèle le déclare comme non nul sans valeur par défaut, Moshi lève une exception au moment de la désérialisation, empêchant les erreurs cachées.
| Caractéristique | Gson | Moshi |
|---|---|---|
| Mécanisme | réflexion | génération de code / réflexion |
| Sécurité nulle | ne prend pas en compte | prise en charge complète de Kotlin |
| Vitesse | moyenne | élevée |
| Valeurs par défaut | non supporté | supporté |
| Kotlin Multiplatform | non | oui |
| Taille de la bibliothèque | ~240 Kb | ~150 Kb |
Le choix entre Moshi et Gson dépend du contexte du projet. Les nouveaux projets en Kotlin bénéficient de Moshi grâce à la sécurité de type et aux performances. Gson reste un choix raisonnable pour prendre en charge le code Java, les structures JSON dynamiques ou lorsque la simplicité de configuration prime sur la vitesse. Pour Kotlin Multiplatform, Moshi est la seule des deux options qui supporte cette plateforme.
Lors de la migration de Gson vers Moshi, les principaux changements concernent les annotations et les adaptateurs. @SerializedName de Gson est remplacé par @Json(name = "..."), et les JsonSerializer/JsonDeserializer personnalisés par la paire @ToJson/@FromJson. Pour les modèles avec valeurs par défaut et champs nullables, Moshi se comporte de manière plus prévisible : si un champ non nul sans valeur par défaut est absent du JSON, Moshi lève une JsonDataException, empêchant les NPE cachés. L’intégration avec Retrofit via MoshiConverterFactory s’ajoute avec une seule dépendance et ne nécessite pas de modifier l’architecture de la couche réseau. Pour l’obfuscation via ProGuard ou R8, il est nécessaire d’ajouter des règles pour préserver les classes annotées avec @JsonClass et les adaptateurs générés, sinon la sérialisation échouera dans la version release. Dans l’ensemble, la migration de Gson vers Moshi est justifiée dans les nouveaux projets Kotlin où les performances et la sécurité de type sont importantes.
// Comparaison de sérialisation : Gson vs Moshi
data class Sample(
val name: String,
val count: Int,
val tags: List<String> = listOf()
)
// Gson : fonctionne par réflexion
val gson = Gson()
val fromGson = gson.fromJson("""{"name":"test"}""",
Sample::class.java)
// count = 0 (par défaut), mais la sécurité nulle n’est pas vérifiée
// Moshi : nécessite un adaptateur, la sécurité nulle est explicite
@JsonClass(generateAdapter = true)
data class SampleMoshi(
val name: String,
val count: Int,
val tags: List<String> = listOf()
)
Questions fréquentes
Moshi est une bibliothèque JSON de Square pour Kotlin et Android qui utilise la génération de code au lieu de la réflexion. Elle offre des performances élevées, un traitement correct de la sécurité nulle de Kotlin et une compatibilité avec Kotlin Multiplatform.
Moshi surpasse Gson en vitesse (2 à 5 fois plus rapide grâce à la génération de code), en sécurité (respecte les annotations nulles de Kotlin) et en taille (~90 Kb plus petit). Moshi prend également en charge Kotlin Multiplatform et les valeurs par défaut dans les data class.
@JsonClass(generateAdapter = true) demande à Moshi de générer un adaptateur pour la classe donnée à la compilation. L’adaptateur généré effectue la sérialisation directement, sans réflexion, offrant des performances maximales.
Créez une classe avec des méthodes annotées avec @ToJson (sérialisation) et @FromJson (désérialisation). Enregistrez l’instance via Moshi.Builder.add(). Moshi trouvera et appliquera automatiquement l’adaptateur lors du traitement du type correspondant.
Oui, Moshi supporte Kotlin Multiplatform depuis la version 1.13.0. Cela en fait la seule solution JSON populaire pour les projets KMP, permettant d’utiliser un code de sérialisation commun sur toutes les plateformes cibles.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi