“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 ~~