Moshi: Modernizzazione dell’analisi JSON su Android

Per lo sviluppo di qualsiasi applicazione è necessario utilizzare JSON per comunicare con il backend e, fino ad ora, la solita cosa era di aiutare se stesso dal GSON biblioteca. Sebbene questo strumento funziona correttamente in Java, non è l’opzione migliore per Kotlin, perché potrebbero apparire errori incontrollati. Negli ultimi tempi, sono stati sviluppati altri strumenti che consentono la stessa cosa, ma sono più sicuri prima di questo tipo di fallimento. Stiamo parlando di Jackson, Kotlinx.Serializzazione e Moshi. Sebbene queste tre opzioni presentano gli stessi vantaggi rispetto a GSON, ci concentreremo su Moshi per essere il più popolare e il più stabile ora.

Cos’è Moshi?

Moshi è un bookstore a Metti in pausa JSON sugli oggetti Java o Kotlin. È sviluppato da Square per quasi le stesse persone che GSON. I principali sviluppatori, Jesse Wilson e Jake Wharton, hanno detto che Moshi poteva essere considerato GSHI V3.

I principali vantaggi su GSON sono:

  • Moshi capisce e funziona correttamente con Tipi nulli di kotlin.
  • Non è più necessario indicare al proguardare che non offre il pacco in cui si trova i tuoi modelli, poiché con la configurazione di base è sufficiente.
  • Moshi nello sviluppo e nel miglioramento, mentre GSON è praticamente una libreria finita.
  • occupa meno dimensione nell’apk.

** (Jesse Wilson espone più vantaggi qui).

Se sei abituato a usare GSON non avrai problemi a usare Moshi, come sembrano molto simili. Tuttavia, è necessario prendere in considerazione alcune differenze e adottare determinate precauzioni quando si effettuano una migrazione.

utilizzando la libreria

Si consiglia di utilizzare Moshi insieme Codegen: https://github.com/square/moshi#codegen

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

e mai dimenticare Aggiungi le regole di PROGUARD: https://github.com/square/moshi/blob/master/moshi/src/main/resources/ME. ..

Per usarlo insieme a Retrofit Utilizzare questo convertitore: https://github.com/square/retrofit/tree/master/retrofit-converters/moshi

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

e aggiungere all’istanza di retrofit come segue:

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

Con questo hai già il tuo progetto pronto all’uso Moshi per fermare il tuo JSON.

Differenze con GSON: Modelli

Dove con GSON avevamo:

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

Con Moshi abbiamo:

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

L’annotazione @SerializedName modifiche di @Json e perché usiamo Codegen, è necessario Scrivi tutte le classi con @JsonClass(generateAdapter = true.

di Fecer con GSON: Deserializzalizzatore / serializzatore

con gson verrà messo in questo modo:

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)!! }}

e con Moshi questo:

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)!! }}

Differenze con GSON: Kotlin NULL SICUREZZA

GSON non capisce i tipi non nullo di Kotlin. Ciò significa che se cerchiamo di deserializzare un valore nullo in una velocità non nullabile, GSON lo renderà senza errori, il che può causare facilmente eccezioni impreviste. Ad esempio:

Dato il modello Foodto precedente e un JSON {“ID”: 0, “Nome”: NULL}:

  • GSON creerà l’oggetto FoodO ( 0, NULL), anche se questo non dovrebbe essere possibile dal momento che il nome è stato definito come non nullible. Non avrà alcuna eccezione ma se riceverai errori quando si utilizza il nome:
    • name.dempty () produrrà un nullpointerException
    • name.trim () lancerà un typecastexception: NULL non può essere cast to non-null tipo kotlin.chosequence
  • moshi avvia la seguente eccezione quando si deseializzante:
    com.squareup.moshi.JsonDataException: Required value 'name' (JSON name 'nombre') missing

con Moshi sapremo dal primo momento che è ciò che fallisce nella definizione del nostro modello, tuttavia con GSON non saremo consapevoli fino al momento dell’uso della variabile e può verificarsi ovunque nel codice e essere in grado di lanciare diversi tipi di errore in base all’uso della variabile e tutto ciò accadrà mentre ti chiedi come è stato possibile per una variabile non nullo essere null.

migrazione da gson

Poiché Moshi è più rigoroso non è raccomandato di creare una massiccia migrazione di tutti gli oggetti che hai in Java o Kotlin poiché è possibile che i tuoi modelli non siano ben definiti.

di Esempio, se i tuoi modelli hanno definito variabili non nullibili che ad un certo punto sono nullo ma non sono mai stati usati, con GSON non avrai mai saltato l’errore e questo sarà stato nascosto, ma se lo stesso modello la migra la migrazione su Moshi l’errore salterà a Moshi. Anche così, ci sono diverse opzioni:

  • se il tuo modello è in Java: convertendolo in Kotlin con tutti i tuoi attributi nullible.
  • I tuoi modelli sono in Kotlin e il codice Ciò li usa è anche in Kotlin: rimuovere gli attributi che non usano o rendono tutti nullibili.
  • Esegui una migrazione progressiva: inizia a utilizzare Moshi nel Parse di nuove richieste e lasciare i vecchi con GSON, ma considerando che non dovrebbero essere miscelati nello stesso modello.
  • Esegui I test ai tuoi modelli sono sicuri del 100% che sono ben definiti e quindi migrano senza paura di rompere nulla.

migrazione progressiva

di questa soluzione avremo un Annotazione con cui diremo a retrofit Quali sono le chiamate che vogliamo analizzare con Moshi.

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

Per funzionare dobbiamo creare il nostro convertitore. Fabbrica per il controllo del controllo Se un servizio è segnato con @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 }}

Finalmente lo inseriamo sulla nostra istanza di retrofit:

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

In questo modo i nuovi servizi che stai implementando nelle tue app possono utilizzare Moshi e gli antichi continuano a utilizzare GSON e ti consente anche di migrare uno per uno s Ervicios.

Migrazione con test

Il primo passo sarebbe quello di fare un test per verificare che la definizione del nostro modello corrisponda a ciò che restituisce il server. Per questo avremo solo bisogno di junit e un file .json che è la copia di ciò che il servizio ci riporta. Mettiamo il nostro precedente modello di cibo e aggiungere il seguente “foo.json” all’interno della cartella delle risorse di test, sarebbe in “Test / Risorse / Foo.json”

{ "id": 0, "name": "SDOS" }

La nostra classe di test sarebbe come questa:

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 variabile GSON deve essere la stessa che la usi in retrofit, nel caso di non farlo Avere il numero Gonsbuilder (). Creare () è quello che viene creato per impostazione predefinita.

Ciò che stiamo facendo sta leggendo il file “foo.json”, diciamo a Gon di deseriabililizzarlo in Foodto e il risultato Nella variabile corrente. Nel previsto abbiamo creato un obiettivo che speriamo che sia il risultato di deseriabilizzare il JSON e abbiamo finalmente controllato con Junit che entrambi i modelli sono uguali.

Una volta che abbiamo i nostri test possiamo già migrare il cibo per usarlo con Moshi e il nostro tipo di test sarebbe come questo:

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) }}

AS PRIMA, MOSHI deve essere lo stesso che usi in retrofit e Moshi.Builder (). Build () è quello che viene creato per impostazione predefinita. L’idea del test è ancora la stessa, ma ora usiamo Moshi per deserializzare il JSON.

Pertanto, più test con diversi tipi di risposte dal tuo server che hai migliori e probabilmente puoi scoprire Errori nei tuoi modelli prima di migrare verso Moshi.

Conclusioni

L’arrivo di Kotlin ha lasciato la prova delle carenze GSON, che possono essere risolte usando nuove librerie, come Moshi. Moshi è una sicurezza nulla, quindi forze per avere modelli ben definiti, evitando così l’emergere di errori inaspettati. È usato in modo simile a GSON, ma evita di aggiungere eccezioni al proguard. Inoltre, è possibile coesistere con GSON e diventare una migrazione progressiva.

GSON è stato un buon compagno di viaggio ma è ora di usare altre alternative. Ora hai gli strumenti di base per provare Moshi e controlla i loro vantaggi per voi stessi.

Speriamo che tu sia stato interessante il nostro post su Moshi. Hai intenzione di usare o preferisci altre librerie? Lasciaci un commento con la tua esperienza o opinione a riguardo!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *