在 JSON 中,值必须是以下数据类型之一:
字符串
数字
对象(JSON 对象)
数组
布尔
Null
JSON 的值不可以是以下数据类型之一:
函数
日期
undefined
参考链接:JSON 数据类型
后台返回数据,有的时候受语言限制或者代码没写好的原因,该返回字符串的但是返回null。返回number的但返回字符串,导致客户端序列化对象的时候出现异常
举个栗子,json数据如下:
{
"tempInt":"",
"tempString":1111,
"tempAs":[
{
"tempInt":"",
"tempString":1111
}
],
"tempA":{
"tempInt":"",
"tempString":1111
}
}
对应的kotlin对象如下
class TestData {
var tempInt: Int? = 0
var tempString: String? = ""
var tempA: A? = null
var tempAs: List<A>? = null
class A {
var tempInt: Int? = 0
var tempString: String? = ""
override fun toString(): String {
return "A(tempInt=$tempInt, tempString=$tempString)"
}
}
}
测试代码如下:
@JvmStatic
fun main(args: Array<String>) {
val testData = gson.fromJson(
"{\n" +
" \"tempInt\":\"\",\n" +
" \"tempString\":1111,\n" +
" \"tempAs\":[\n" +
" {\n" +
" \"tempInt\":\"\",\n" +
" \"tempString\":1111\n" +
" }\n" +
" ],\n" +
" \"tempA\":{\n" +
" \"tempInt\":\"\",\n" +
" \"tempString\":1111\n" +
" }\n" +
"}", TestData::class.java
)
System.out.println(testData.tempString + "=======" + testData.tempInt)
System.out.println(testData.tempA?.toString() + "=======" + testData.tempA?.tempInt)
System.out.println(testData.tempAs.toString())
}
不处理,就会提示如下报错
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String
at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:228)
at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:218)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
at com.google.gson.Gson.fromJson(Gson.java:927)
at com.google.gson.Gson.fromJson(Gson.java:892)
at com.google.gson.Gson.fromJson(Gson.java:841)
at com.google.gson.Gson.fromJson(Gson.java:813)
at com.ziqi.baselibrary.util.gson.GsonUtil.main(GsonUtil.kt:42)
Caused by: java.lang.NumberFormatException: empty String
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at com.google.gson.stream.JsonReader.nextInt(JsonReader.java:1201)
at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:226)
... 8 more
但是通过GsonBuilder实现创建gson对象,并使用TypeAdapter来处理每个基本类型,就不会有上面的异常
val gson: Gson = GsonBuilder() //配置你的Gson
.registerTypeAdapter(Int::class.java, IntAdapter())
.registerTypeAdapter(Integer::class.java, IntAdapter())
.registerTypeAdapter(String::class.java, StringAdapter())
.registerTypeAdapter(Double::class.java, DoubleAdapter())
.create()
没有异常并输出内容
1111=======-1
A(tempInt=-1, tempString=1111)=======-1
[A(tempInt=-1, tempString=1111)]
因为一般只会用double,long,int,string这几个基本类型,我就整理封装了一下
DoubleAdapter.kt
package com.ziqi.baselibrary.util.gson
import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import java.io.IOException
class DoubleAdapter : TypeAdapter<Double?>() {
@Throws(IOException::class)
override fun write(out: JsonWriter?, value: Double?) {
try {
var tempValue = value
if (tempValue == null) {
tempValue = -1.0
}
out?.value(tempValue)
} catch (e: Exception) {
}
}
@Throws(IOException::class)
override fun read(`in`: JsonReader): Double? {
var value: Double? = -1.0
try {
if (`in`.peek() == JsonToken.NULL) {
`in`.nextNull()
value = -1.0
} else if (`in`.peek() == JsonToken.BOOLEAN) {
val b = `in`.nextBoolean()
value = if (b) 1.0 else 0.0
} else if (`in`.peek() == JsonToken.STRING) {
try {
value = `in`.nextString().toDouble()
} catch (e: Exception) {
value = -1.0
}
} else {
value = `in`.nextDouble()
}
} catch (e: Exception) {
value = -1.0
}
return value
}
}
IntAdapter.kt
package com.ziqi.baselibrary.util.gson
import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import java.io.IOException
class IntAdapter : TypeAdapter<Int?>() {
@Throws(IOException::class)
override fun write(out: JsonWriter?, value: Int?) {
try {
var tempValue = value
if (tempValue == null) {
tempValue = -1
}
out?.value(tempValue)
} catch (e: Exception) {
}
}
@Throws(IOException::class)
override fun read(`in`: JsonReader): Int? {
var value: Int? = -1
try {
if (`in`.peek() == JsonToken.NULL) {
`in`.nextNull()
value = -1
} else if (`in`.peek() == JsonToken.BOOLEAN) {
val b = `in`.nextBoolean()
value = if (b) 1 else 0
} else if (`in`.peek() == JsonToken.STRING) {
try {
value = `in`.nextString().toInt()
} catch (e: Exception) {
value = -1
}
} else {
value = `in`.nextInt()
}
} catch (e: Exception) {
value = -1
}
return value
}
}
LongAdapter.kt
package com.ziqi.baselibrary.util.gson
import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import java.io.IOException
class LongAdapter : TypeAdapter<Long?>() {
@Throws(IOException::class)
override fun write(out: JsonWriter?, value: Long?) {
try {
var tempValue = value
if (tempValue == null) {
tempValue = -1
}
out?.value(tempValue)
} catch (e: Exception) {
}
}
@Throws(IOException::class)
override fun read(`in`: JsonReader): Long? {
var value: Long? = -1
try {
if (`in`.peek() == JsonToken.NULL) {
`in`.nextNull()
value = -1
} else if (`in`.peek() == JsonToken.BOOLEAN) {
val b = `in`.nextBoolean()
value = if (b) 1 else 0
} else if (`in`.peek() == JsonToken.STRING) {
try {
value = `in`.nextString().toLong()
} catch (e: Exception) {
value = -1
}
} else {
value = `in`.nextLong()
}
} catch (e: Exception) {
value = -1
}
return value
}
}
StringAdapter.kt
package com.ziqi.baselibrary.util.gson
import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
class StringAdapter : TypeAdapter<String?>() {
override fun write(out: JsonWriter?, value: String?) {
try {
var tempValue: String? = value
if (tempValue == null) {
tempValue = ""
}
out?.value(tempValue)
} catch (e: Exception) {
}
}
override fun read(`in`: JsonReader?): String? {
var value: String? = ""
try {
if (`in`?.peek() == JsonToken.NULL) {
`in`.nextNull()
value = ""
} else if (`in`?.peek() == JsonToken.BOOLEAN) {
val b = `in`.nextBoolean()
value = b.toString()
} else if (`in`?.peek() == JsonToken.NUMBER) {
try {
value = `in`.nextLong().toString()
} catch (e: Exception) {
value = ""
}
} else {
value = `in`?.nextString()
}
} catch (e: Exception) {
value = ""
}
return value
}
}
解决了基本的类型,还有2个对象没处理
对象(JSON 对象)
数组
使用JsonDeserializer接口类,实现判断isJsonArray和isJsonObject
修改后的Gson对象代码
val gson: Gson = GsonBuilder() //配置你的Gson
.setDateFormat("yyyy-MM-dd hh:mm:ss")
//https://blog.csdn.net/axxbc123/article/details/84625539
.enableComplexMapKeySerialization()
//https://blog.csdn.net/u010502101/article/details/80555558
.serializeNulls()
.registerTypeAdapter(Int::class.java, IntAdapter())
.registerTypeAdapter(Integer::class.java, IntAdapter())
.registerTypeAdapter(String::class.java, StringAdapter())
.registerTypeAdapter(Double::class.java, DoubleAdapter())
.registerTypeAdapter(Long::class.java, LongAdapter())
.registerTypeAdapter(List::class.java, ListJsonDeserializer())
.registerTypeAdapter(TestData.A::class.java, ObjectJsonDeserializer<TestData.A>())
.create()
ListJsonDeserializer.java
package com.ziqi.baselibrary.util.gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* https://www.jianshu.com/p/3108f1e44155
*/
public class ListJsonDeserializer implements JsonDeserializer<List<?>> {
@Override
public List<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json.isJsonArray()) {
JsonArray array = json.getAsJsonArray();
Type itemType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
List list = new ArrayList<>();
for (int i = 0; i < array.size(); i++) {
JsonElement element = array.get(i);
Object item = context.deserialize(element, itemType);
list.add(item);
}
return list;
}
return Collections.EMPTY_LIST;
}
}
ObjectJsonDeserializer.java
package com.ziqi.baselibrary.util.gson;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class ObjectJsonDeserializer<T> implements JsonDeserializer<T> {
@Override
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
T temp = null;
if (json.isJsonObject()) {
temp = GsonUtil.INSTANCE.getInnerGson().fromJson(json, typeOfT);
return temp;
}
return temp;
}
}
核心技术点是使用TypeAdapter和JsonDeserializer两个类处理,gson还有很多api可以让我学习的,若有更好的封装代码,希望大佬分享出来
经过以上处理gson后,不管后台返回对象是否正常,我们代码就会变得更健壮起来,最近我在写一个玩Android 这完整代码会在我GitHub上的工程上
WanAndroidKotlin
我是分了模块开发的,在baselibrary模块里面
网友评论