MosHI: Modernisation de l’analyse JSON sur Android

Pour le développement de toute application Il est nécessaire d’utiliser JSON pour communiquer avec le backend et, jusqu’à présent, la chose habituelle était de s’aider à partir du gson bibliothèque. Bien que cet outil fonctionne correctement en Java, ce n’est pas la meilleure option pour Kotlin, car les erreurs non contrôlées peuvent apparaître. Ces derniers temps, d’autres outils ont été développés qui permettent la même chose, mais ils sont plus sûrs avant ce type d’échec. Nous parlons de Jackson, Kotlinx.Sérialisations et Moshi. Bien que ces trois options présentent les mêmes avantages sur GSON, nous nous concentrerons sur MosHI pour être le plus populaire et le plus stable maintenant.

Qu’est-ce que MosHI?

Moshi est une librairie Pause Json sur des objets Java ou Kotlin. Il est développé par carré pour presque les mêmes personnes que GSON. Les principaux développeurs, Jesse Wilson et Jake Wharton, ont déclaré que Moshi pourrait être considéré comme un gson v3.

Les principaux avantages sur GSON sont les suivants:

  • MosHI comprend et fonctionne correctement avec NULL TYPES DE KOTLIN.
  • Il n’est plus nécessaire d’indiquer à PROGUARD qu’il n’offre pas le paquet où vous avez vos modèles, car avec la configuration de base suffit.
  • Moshi dans le développement et l’amélioration, tandis que Gson est pratiquement une librairie finie.
  • occupe moins de taille dans l’APK.

** (Jesse Wilson expose plus d’avantages ici).

Si vous êtes utilisé pour utiliser GSON, vous n’aurez pas de problèmes à l’aide de Moshi, comme ils ressemblent beaucoup. Cependant, il est nécessaire de prendre des différences en compte et de prendre certaines précautions lors de la migration.

à l’aide de la bibliothèque

Il est recommandé d’utiliser MosHI ensemble de CodeGen: https://github.com/square/moshi#codegen

implementation "com.squareup.moshi:moshi:$moshi_version"kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version"

Ajoutez les règles de PROGUARD: https://github.com/square/moshi/blob/master/moshi/src/main/resources/ME. ..

Pour l’utiliser avec la modernisation Utilisez ce convertisseur: https://github.com/square/retrofit/tree/master/retrofit-converters/moshi

implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version"

et ajoutez à votre instance de modernisation comme suit:

Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(MoshiConverterFactory.create()) .build()

Avec ceci, vous avez déjà votre projet prêt à utiliser MosHI pour arrêter votre JSON.

Différences avec GSON: Modèles

Où avec GSON Nous avions:

data class FooDTO( val id: Int, @SerializedName("nombre") val name: String)

avec MosHI Nous avons:

@JsonClass(generateAdapter = true)data class FooDTO( val id: Int, @Json(name = "nombre") val name: String)

l’annotation @SerializedName Modifications de @Json et parce que nous utilisons le codeGen, il est nécessaire de Notez toutes les classes avec @JsonClass(generateAdapter = true.

DI FEUILLES AVEC GSON: Déserializer / Serializer

Avec GSON serait mis de cette façon:

class DateAdapter : JsonDeserializer<Date>, JsonSerializer<Date> { private val df = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()) override fun serialize( src: Date, typeOfSrc: Type, context: JsonSerializationContext ): JsonElement { return JsonPrimitive(df.format(src)) } override fun deserialize( json: JsonElement, typeOfT: Type, context: JsonDeserializationContext ): Date { return df.parse(json.asString)!! }}

class DateAdapter { private val df = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault()) @ToJson fun toJson(value: Date): String { return df.format(value) } @FromJson fun fromJson(source: String): Date { return df.parse(source)!! }}

Différences avec GSON: KOTLIN NULL SECURITE

GSON ne comprend pas les types non nuls de Kotlin. Cela signifie que si nous essayons de désérialiser une valeur nulle dans un taux non valully, le GSON le fera sans erreur, ce qui peut entraîner facilement des exceptions inattendues. Par exemple:

donné le modèle de nourriture précédent et un json {«  » id « : 0, » nom « : null}:

  • gson créera l’objet Foasto ( 0, NULL), bien que cela ne soit pas possible, car le nom a été défini comme non vallonné. Ne se lancera pas d’exception, mais si vous obtiendrez des erreurs lors de l’utilisation du nom:
    • nom.dempty () produira une nullpointException
    • nom.trim () lancera une typastexception: null ne peut pas être Cast to non nul Type Kotlin.chosequence
  • Moshi lancera l’exception suivante lors de la désérialisation:
    com.squareup.moshi.JsonDataException: Required value 'name' (JSON name 'nombre') missing

avec Moshi, nous saurons dès le premier moment, ce qui est ce qui échoue dans la définition de notre modèle, cependant avec GSON, nous ne serons pas au courant du moment de l’utilisation de la variable et peut se produire n’importe où dans le code et Soyez capable de jeter plusieurs types d’erreur en fonction de l’utilisation de la variable et de tout cela se produira pendant que vous vous demandez comment il a été possible pour une variable non nulle d’être null.

Migration de GSON

Parce que Moshi est plus rigoureux n’est pas recommandé de faire une migration massive de tous les objets que vous avez à Java ou Kotlin car il est possible que vos modèles ne soient pas bien définis.

par Exemple, si vos modèles ont défini des variables non nullables qu’à un moment donné sont nuls mais n’ont jamais été utilisés, avec GSON, vous n’aurez jamais sauté l’erreur et cela aura été masqué, mais si ce même modèle vous migrez à MosHI l’erreur. va aller à Moshi. Malgré tout, il existe plusieurs options:

  • Si votre modèle est en Java: la convertir en Kotlin avec tous vos attributs nullables.
  • Vos modèles sont à Kotlin et au code Cela les utilise, il s’agit également de Kotlin: Supprimer les attributs qui ne l’utilisent pas ou ne les rendent pas nullables.
  • Effectuer une migration progressive: commencez à utiliser Moshi dans l’analyse de nouvelles demandes et laissez les anciens avec GSON, mais compte tenu de ne pas être mélangé dans le même modèle.
  • Effectuer tests sur vos modèles pour être à 100% sûr qu’ils sont bien définis et migrent ainsi sans crainte de ne rien casser.

Migration progressive

Par cette solution, nous aurons un Annotation avec laquelle nous allons dire à la modernisation Quels sont les appels que nous voulons analyser avec Moshi.

@Target(AnnotationTarget.FUNCTION)@Retention(RUNTIME)annotation class Moshiinterface GdaxApi { @GET("products") fun products(): List<Product> @Moshi @GET("products") fun productsMoshi(): List<Product>}

Pour que cela fonctionne, nous devons créer notre propre convertisseur. Usine pour vérifier si un service est marqué avec @moshi:

class MoshiMigrationConverter(private val moshiConverterFactory: MoshiConverterFactory) : Converter.Factory() { override fun responseBodyConverter( type: Type, annotations: Array<Annotation>, retrofit: Retrofit): Converter<ResponseBody, *>? { for (annotation in annotations) { if (annotation.annotationClass == Moshi::class) { return moshiConverterFactory.responseBodyConverter(type, annotations, retrofit) } } return null } override fun requestBodyConverter( type: Type, parameterAnnotations: Array<Annotation>, methodAnnotations: Array<Annotation>, retrofit: Retrofit): Converter<*, RequestBody>? { for (annotation in methodAnnotations) { if (annotation.annotationClass == Moshi::class) { return moshiConverterFactory.requestBodyConverter( type, parameterAnnotations, methodAnnotations, retrofit) } } return null }}

enfin, nous l’insérez enfin à notre instance de modernisation:

val retrofit = Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(MoshiMigrationConverter(MoshiConverterFactory.create())) .addConverterFactory(GsonConverterFactory.create()) .build()

De cette manière, les nouveaux services que vous implouillez dans vos applications peuvent utiliser MosHI et les anciens continuent à utiliser GSON et vous permet également de migrer une par une ERVICIOS.

Migration avec des tests

La première étape consisterait à effectuer un test pour vérifier que la définition de notre modèle correspond à ce qui renvoie le serveur. Pour cela, nous aurons seulement besoin de junit et d’un fichier .json qui est la copie de ce que le service nous revient. Placons notre modèle de nourriture précédent et ajoutons le suivant « FOO.JSON » dans le dossier Ressources de test, il serait dans « Test / Ressources / FOO.JSON »

Notre classe de test serait comme ceci:

class FooDTOTest { private val loader = javaClass.classLoader!! private val gson = GsonBuilder().create() @Test fun parse() { val jsonString = String(loader.getResourceAsStream("foo.json").readBytes()) val actual = gson.fromJson(jsonString, FooDTO::class.java) val expected = FooDTO(10, "SDOS") assertEquals(expected, actual) }}

La variable GSON doit être identique à celle que vous l’utilisez dans la modernisation, dans le cas de ne pas Avoir nombre gonsbuilder (). Créer () est celui qui est créé par défaut.

Ce que nous faisons est de lire le fichier « foo.json », nous disons à Gon de le désérialiser dans la nourriture et le résultat Dans la variable actuelle. Nous avons créé un objectif que nous espérons que c’est le résultat de désérialiser le JSON et que nous avons finalement vérifié avec JUNIT que les deux modèles sont égaux.

Une fois que nous avons nos tests, nous pouvons déjà migrer de la nourriture pour l’utiliser avec Moshi et notre type de test seraient comme ceci:

class FooDTOTest { private val loader = javaClass.classLoader!! private val moshi = Moshi.Builder().build() @Test fun parse() { val jsonString = String(loader.getResourceAsStream("foo.json").readBytes()) val actual = moshi.adapter(FooDTO::class.java).fromJson(jsonString) val expected = FooDTO(10, "SDOS") assertEquals(expected, actual) }}

Comme avant, Moshi doit être identique à celui que vous utilisez dans la modernisation et MosHI.Builder (). Construire () est celui qui est créé par défaut. L’idée du test est toujours la même, mais nous utilisons maintenant Moshi pour désérialiser le Json.

Par conséquent, plus les tests avec différents types de réponses de votre serveur vous avez mieux et vous pouvez probablement découvrir Erreurs dans vos modèles avant de migrer vers Moshi.

Conclusions

L’arrivée de Kotlin a laissé des preuves de lacunes de Gson, qui peuvent être résolues à l’aide de nouvelles librairies, telles que MosHI. Moshi est une sécurité nulle, elle obligeait donc à avoir des modèles bien définis, évitant ainsi l’émergence d’erreurs inattendues. Il est utilisé de la même manière à GSON, mais évitez d’ajouter des exceptions à Proguard. De plus, vous pouvez coexister avec GSON et devenir une migration progressive.

GSON a été un bon compagnon de voyage, mais il est temps d’utiliser d’autres alternatives. Maintenant, vous avez les outils de base pour essayer Moshi et vérifier leurs avantages pour vous-mêmes.

Nous espérons avoir été intéressant notre message sur Moshi. Allez-vous utiliser ou préférez-vous d’autres librairies? Laissez-nous un commentaire avec votre expérience ou votre opinion à ce sujet!

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *