“If you’re using Kotlin, you’re still using Gson.”

What is the Moshi

One-sentence description

Moshi is an open source library that implements serialization and deserialization of Json

As you all know, Moshi essentially did the same thing

(This article is based on the use of Moshi have some simple understanding of the basis, if you have not known about Moshi, it is recommended to see this article a new generation of Json parsing library Moshi use and principle analysis)

Why use a Moshi

One-sentence description

Gson is a Json serialization and deserialization library for Java

Moshi is a Json serialization and deserialization library for Kotlin

In today’s world of higher level languages, especially Kotlin, which is still essentially Java, but with its easy-to-use apis and syntax-sugar, it’s a lot of fun. The old Gson is a little out of its depth when it comes to Kotlin serialization. There are two main problems:

(1) Air safety issues

Kotlin divides variables into nullable and non-nullable types, whereas virtually all variables in Java are nullable (except for the @nonnullable tag). If a variable in Json has a null value, but Kotlin declares that the variable is non-null, Gson will still assign the variable to null

(2) Default parameters are invalid

The default argument is a new syntax for Kotlin. When you define a data class, you assign default values to the arguments in the constructor. Such as:

class People(val name:String, val age:Int = 18)
Copy the code

When the Json is:

{"name" : "ha ha ha"}Copy the code

According to Kotlin’s syntax, the desired object is

People(name=" hahahaha ", age = 18)Copy the code

But in fact Gson is going to parse into

People(name=" ha ha ha ", age = 0)Copy the code

This causes the default age = 18 parameter to be lost

To make Json parsing more syntactically compliant with Kotlin, Moshi was chosen

How does Moshi implement deserialization

At this point the curious brother may ask

Why is Moshi’s parsing more consistent with Kotlin’s syntax? It’s a match, isn’t it?

Wait, wait, wait. To figure this out, you need to know how Moshi implements deserialization

Let’s first look at a simple use of Moshi deserialization:

Val json = "{"name": "name", "age": 18, "email": }" // Model class People(val name:String, val age:Int){val email: String = ""} // Deserialize fun parseModel(json: String): People? { val moshi = Moshi.Builder().addLast(KotlinJsonAdapterFactory()).build() val adapter = moshi.adapter(People::class.java) val people = adapter.fromJson(json) return people }Copy the code

The Model class contains a hidden pit.

An older brother who has never used Moshi might be offended by this behavior, “Just give me a few lines of code or not? Am I someone who reads code and remembers it? !”

Don’t hurry, I’ll break it off for you bit by bit and crumple it. You’ll lie down comfortably

There are two main things unfamiliar here. KotlinJsonAdapterFactory and adapter.

The KotlinJsonAdapterFactory is the factory that generates the JsonAdapter

2 val adapter = moshi.adapter(People::class.java) 2 val adapter = moshi.adapter(People::class.java

(3) Adapter calls its own fromJson and toJson methods to complete the serialization and deserialization process.

Translating the above code into a flowchart would be:

The Moshi deserialization process is that simple!

Check the object

With Moshi’s deserialization process in mind, let’s answer the above brother’s question

Why is Moshi better suited to Kotlin syntax?

Going back to the example used by Moshi, what is the result of deserialization?

People(name=” [email protected]”, age = 18) email =” [email protected]

People(name= People, age = 18) email =” “

We analyze from Kotlin syntax that email is immutable to val. Serialization is essentially creating an object and assigning it to json, so will Moshi assign an immutable email

The answer is no.

If you’re bold enough to see that KotlinJsonAdapterFactory is generating a JsonAdapter, there is a process of “checking if the object is legitimate”. I’ll sneak in a line of source code from this process:

// In: kotlinJsonAdapterFactorycreate () if (property! is KMutableProperty1 && parameter == null) continueCopy the code

Ah ah ah, I am not the title party, this is not source code, is English English, do not believe me to explain to you

Propery — represents all the member properties in the data class. Val name:String, val age:Int and var email :String = “”

KMutableProperty1 — is a type object in Kotlin. Var is the mutable type

Parameter — Represents the parameters in the constructor. Val name:String, val age:Int (parameter == null)

Continue — skip. I’m not deserializing this property

So in the language of the Han, one of the 56 ethnic groups of the great People’s Republic of China:

If a member attribute is immutable (that is, val) and not declared in the constructor, skip it

As you can see, the KotlinAdapterJsonFactory is actually one of the key things that distinguishes it from Gson. It does some validation on class objects to make Moshi more Kotlin compliant

truly

The KotlinJsonAdapter, another core of Moshi, is the true implementation of Model serialization and deserialization

The core of adapter is binding

Here we can think of an analogy with Model. A Model corresponds to an Adapter, and the member properties in the Model are Binding

Binding is responsible for parsing the basic data types. IntBinding contains an IntAdapter that parses the int type in json. StringBinding has a StringAdapter that parses strings in JSON.

In general, Binding takes the type and value of a field in JSON and saves it yourself

As for how to identify the types and values of the fields in json, Moshi is basically a copy of Gson’s JsonReader and JsonWriter

The KotlinJsonAdapter generates a class object by reflection. These bindings assign the values of the member properties to each property, and eventually produce a Model object.

And so on and so on. Generating objects by reflection? Why so abstract?

It’s easy. This is actually a call to Android’s Constructor method newInstance(*args)

As long as there are class objects, generating instance objects is a one-sentence matter

People: : class. Java. Constructors [1]. The newInstance (" zhang ", // Constructors [0] are constructors with the most parameters // The third parameter indicates the number of constructors with the default parameter values // So the result is: People (" zhang ", 18) People: : class. Java constructors [0]. NewInstance (" zhang ", 20, 2, null)Copy the code

So far, we’ve basically gone through the process of deserializing a Moshi. Try not to post a large section of code, is not to want everyone in a very difficult to chew through the source code, after a few weeks to feel plausible, half-understand

So I hope to be able to give you a simple system, there are some have to use the source code is to try to give a common explanation.

Code is only the implementation of details, is the knowledge system branches. If you want to dig deeper into some of the details, read the following

// Generate adapter KotlinJsonAdapterFactory#create() // serialize and deserialize adapter: KotlinJsonAdapter#fromJson KotlinJsonAdapter#toJson // reflect generated objects KCallableImpl#callBy#callDefaultMethod CallerImpl>Constructor#call Constructor#newInstanceCopy the code

I didn’t post the code, it’s for you to read

I am the wood

Don’t like large sections of source code

I want to describe the technology in plain language

I want to write something that makes me happy and makes everyone happy

Welcome to like ~~