A problem that needs to be avoided when using JSONObject

A problem that needs to be avoided when using JSONObject

About the author: Bao Xiehao, Xiaomi MIUI department, MIUI basic application group address book development leader

[[179904]]

Problem phenomenon

In the logic code of Android business synchronization, JSONObject is used to parse the JSON data on the server side. At the same time, due to the new business requirements, JSONObject is used in the local database to cache synchronization-related information including water level, where the water level value is Long type. However, it was recently discovered that during the next synchronization process, the water level passed to the server is not the new water level returned by the server last time, but a little different. Take 301028292893495297L as an example. After the server returns this water level, the water level uploaded by the client next time is 301028292893495296L, and the difference is -1.

Troubleshooting

By repeatedly checking the code logic, we found that the water level only went through the following conversions from the time the server returned to the time the next request was made:

If you read the code carefully, you will find that the Long water level value is converted to String when it is saved in the JSON object, and is treated as Long when it is read. Therefore, there will be a problem of precision loss, see the following JSONObject documentation:

It can be seen that when reading a value of a JSON object, if it is originally a String type, it will be read as a Long type and the String type will be parsed through Double, so there will be a problem of precision loss when the value exceeds 2^52. So, the problem encountered can be explained. The following is the storage format specification of Double:

The precision test code for Double and Long is very simple (the input parameter can provide a long value exceeding 2^52 such as 301028292893495297L, and its return value is not 0):

The precision test code for Double and Long is very simple (the input parameter can provide a long value greater than 2^52 such as 301028292893495297L):

Knowing the root cause of the problem, the fix is ​​clear. When the water level is saved in the JSONObject object, it should be saved as a Long type instead of a String type; or when reading it, it should also be treated as a String type and then parsed through interfaces such as Long.valueOf.

In addition, it is easy to overlook whether the value in the JSON object is of Long type or String type. If the JSON object is represented by a String, the value is of String type if there are quotation marks around it. The following trial example will make it clear:

If you search for similar questions on the Internet, you will find that many people have encountered problems, such as this one.

Therefore, although we cannot say that the design of this library is a failure, it is certainly not a well-designed library. Because you cannot directly see the underlying logic of the API name, it is easy to cause users to use it improperly. Therefore, the lesson learned is: when using third-party libraries, read the API documentation if you can, and do not take the words literally. Of course, this problem may only be limited to older code modules in Android. After all, new code will use libraries such as GSON to operate JSON objects, so it is not easy to have such difficult-to-find problems.

Of course, looking at this problem alone, it is actually that when adding business logic, the interface of the JSONObject object is not used correctly. The Long value should not be saved as a String type and read as a Long type. If the saving and reading interfaces are kept corresponding, there will be no problem. In any case, the lesson of this problem is to be extra careful when using JSONObject related interfaces.

Note: The latest JSON-Java library on Github does not have this problem and can be used without any worries.

Problem Solving

Knowing the root cause of the problem, the fix is ​​clear. When the water level is saved in the JSON object, it should be saved as a Long type instead of a String type; or it should also be read as a String type and then parsed through interfaces such as Long.valueOf.

Afterword

If you search for similar problems online, you will find that many people have encountered the same problem, such as this one. Therefore, although we cannot say that the design of this library is a failure, it is definitely not a well-designed library. Because you cannot directly see the underlying logic from the API name, it leads to improper use. Therefore, the lesson is: when using a third-party library, read the API documentation if you can, and do not take it literally.

Of course, the popular JSON-Java library on Github does not have this problem.

<<:  A new method to improve the survival rate of Android application processes (Part 2)

>>:  iOS 10.2 may cause more iPhones to suddenly shut down

Recommend

Those practical skills for APP operation and promotion are worth collecting!

Regarding the operation and promotion of APP, the...

How to operate content well and create phenomenal products

In my past work experience, I have always been th...

Introduction to Qinggua Media’s intelligent advertising delivery system!

Introduction to Qinggua Media Intelligent Adverti...

Wi-Fi Master Key: How to crack it and whether it is dangerous

Why can this "key" crack Wi-Fi? Does it...

3 tips for a successful marketing campaign!

What are the elements of a successful marketing c...

You stay at home with your cat, the cat: emmm, it’s too annoying

Cat lovers are often associated with sensitive, q...