In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-14 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly introduces "how to solve the problems caused by Gson". In daily operation, I believe many people have doubts about how to solve the problems caused by Gson. The editor consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful for you to answer the doubts about "how to solve the problems caused by Gson"! Next, please follow the editor to study!
I. the origin of the problem
Let's take a look at a very simple model class, Boy:
Public class Boy {public String boyName; public Girl girl; public class Girl {public String girlName;}}
There are usually a lot of model classes in a project, such as each card on the interface, which parses the data returned by Server, and then parses out each card model, right?
For parsing Server data, in most cases, Server returns a json string, while our client uses Gson for parsing.
So let's take a look at the above example of the Boy class, the code parsed by Gson:
Public class Test01 {public static void main (String [] args) {Gson gson = new Gson (); String boyJsonStr = "{\" boyName\ ":\" zhy\ ",\" girl\ ": {\" girlName\ ":\" lmj\ "}}"; Boy boy = gson.fromJson (boyJsonStr, Boy.class); System.out.println ("boy name is =" + boy.boyName + ", girl name is =" + boy.girl.girlName) " }}
What is the result of the operation?
Let's take a look:
Boy name is = zhy, girl name is = lmj
It's very normal, ha, in line with our expectations.
Suddenly, one day, a classmate added a method getBoyName () to the girl class to get the name of the girl's favorite boy, which is very simple:
Public class Boy {public String boyName; public Girl girl; public class Girl {public String girlName; public String getBoyName () {return boyName;}
It seems that there is nothing wrong with the code, and if you ask me to add getBoyName () on this basis, maybe the code is written in the same way.
However, such code buries a deep hole.
What kind of pit?
Going back to our previous test code, we now try to parse the completed json string and call girl.getBoyName ():
Public class Test01 {public static void main (String [] args) {Gson gson = new Gson (); String boyJsonStr = "{\" boyName\ ":\" zhy\ ",\" girl\ ": {\" girlName\ ":\" lmj\ "}}"; Boy boy = gson.fromJson (boyJsonStr, Boy.class); System.out.println ("boy name is =" + boy.boyName + ", girl name is =" + boy.girl.girlName) " / / add System.out.println (boy.girl.getBoyName ());}}
It's very simple, adding a line to print.
This time, what do you think is the result of the operation?
Still no problem? Of course not, and as a result:
Boy name is = zhy, girl name is = lmj Exception in thread "main" java.lang.NullPointerException at com.example.zhanghongyang.blog01.model.Boy$Girl.getBoyName (Boy.java:12) at com.example.zhanghongyang.blog01.Test01.main (Test01.java:15)
Boy$Girl.getBoyName reported npe, is girl null? Obviously not, we printed girl.name on it, and it's even less likely that boy is null.
That's strange. There's only one line of code in getBoyName:
Public String getBoyName () {return boyName; / / npe}
Who on earth is null?
Second, a puzzling null pointer
Return boyName; can only guess that it is an object. BoyName, which is null.
Who is this certain object?
Let's take a fresh look at getBoyName (), which returns the boyName field of the boy object. This method should be written in more detail as follows:
Public String getBoyName () {return Boy.this.boyName;}
So, now it's clear that the object Boy.this is null.
* * so the question is, why should this object be null after being serialized by Gson? * *
If you want to figure this out, there is another antecedent question:
Why can we access the properties and methods of the external class Boy in the Girl class?
Third, some secrets of non-static inner classes
The best way to explore the secrets of Java code is to look at bytecode.
Let's go down and take a look at the Girl bytecode to see how the "culprit" getBodyName () is written.
Javap-v Girl.class
Look at the bytecode of getBodyName ():
Public java.lang.String getBoyName (); descriptor: () Ljava/lang/String; flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield # 1 / / Field this$0:Lcom/example/zhanghongyang/blog01/model/Boy 4: getfield # 3 / / Field com/example/zhanghongyang/blog01/model/Boy.boyName:Ljava/lang/String; 7: areturn
You can see aload_0, which must be the this object. Then getfield gets the this0 field, then through the this0 field, through the this0 field, and then through this0 to getfield to get the boyName field, that is to say:
Public String getBoyName () {return boyName;}
Equivalent to:
Public String getBoyName () {return $this0.boyName;}
So where did this $this0 come from?
Let's take a look at the member variable of Girl's bytecode:
Final com.example.zhanghongyang.blog01.model.Boy this$0; descriptor: Lcom/example/zhanghongyang/blog01/model/Boy; flags: ACC_FINAL, ACC_SYNTHETIC
Sure enough, there is a this$0 field, at this time you get confused, my code does not have ah?
We'll explain later.
Let's see where this this$0 can be assigned.
After flipping through the bytecode, it is found that the construction method of Girl is as follows:
Public com.example.zhanghongyang.blog01.model.Boy$Girl (com.example.zhanghongyang.blog01.model.Boy); descriptor: (Lcom/example/zhanghongyang/blog01/model/Boy;) V flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: aload_1 2: putfield # 1 / / Field this$0:Lcom/example/zhanghongyang/blog01/model/Boy 5: aload_0 6: invokespecial # 2 / / Method java/lang/Object. ": () V 9: return LineNumberTable: line 8: 0 LocalVariableTable: Start Length Slot Name Signature 0 100 this Lcom/example/zhanghongyang/blog01/model/Boy$Girl; 0 101 this$0 Lcom/example/zhanghongyang/blog01/model/Boy
You can see that this constructor contains a formal parameter, the Boy object, which will eventually be assigned to our $this0.
And let's send the next thing, let's take a look at the Girl bytecode as a whole:
Public class com.example.zhanghongyang.blog01.model.Boy$Girl {public java.lang.String girlName; final com.example.zhanghongyang.blog01.model.Boy this$0; public com.example.zhanghongyang.blog01.model.Boy$Girl (com.example.zhanghongyang.blog01.model.Boy); public java.lang.String getBoyName ();}
There is only one constructor, which is the constructor that we just said needs to be passed in the Boy object.
This piece has a little knowledge that not all objects that do not write the construction method will have a default no-parameter construction.
In other words:
If you want to construct a normal Girl object, you theoretically have to pass in a Boy object.
So normally if you want to build a Girl object, you have to write the Java code like this:
Public static void testGenerateGirl () {Boy.Girl girl = new Boy () .new Girl ();
There must be body before there can be girl.
Now that we've figured out the secret of non-static inner classes calling external classes, let's think about why Java is designed this way.
Because Java supports non-static inner classes, and the inner class can access the properties and variables of the external class, but after compilation, the internal class will actually become an independent class object, such as the following figure: so that another class can access the members of another class, then the accessed object must be passed in, and it must be passed in, then the only construction method is the most appropriate.
You can see the Java compiler in order to support some features, behind the silent support, in fact, this support is not only this, a lot of places can see, and some of these variables and methods added during compilation, there will be a modifier to modify: ACC_SYNTHETIC.
If you don't believe it, take a closer look at the statement of $this0.
Final com.example.zhanghongyang.blog01.model.Boy this$0; descriptor: Lcom/example/zhanghongyang/blog01/model/Boy; flags: ACC_FINAL, ACC_SYNTHETIC
At this point, we have fully understood the process. It must be that Gson does not pass in the body object when deserializing the string into an object, and then causes $this0 to be null all the time. When we call the member methods and member variables of any external class, we throw you a NullPointerException.
4. How does Gson construct non-static anonymous inner class objects?
Now I'm just curious, because we've seen that Girl is constructed without parameters, only a constructor that contains Boy parameters, so how is the Girl object Gson created?
Is to find the constructor with the Body parameter, and then reflect newInstance, except that the Body object passes in null?
It seems to make sense, let's take a look at the code to see if this is the case:
I'll make a long story short:
Gson to build objects, one is to find the type of object, and then find the corresponding TypeAdapter to deal with, in this case our Girl object, will eventually go to ReflectiveTypeAdapterFactory.create and return a TypeAdapter.
I can only carry it again:
# ReflectiveTypeAdapterFactory.create @ Override public TypeAdapter create (Gson gson, final TypeToken type) {Class
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.