由于近期对平台内容进行审核,导致之前的这篇文章无法访问,所以重新发一次
android开发的数据几乎都是通过请求拿到后台的json数据,然后将数据解析成对应的Bean
通常我们会将请求结果封装成一个BaseResponse,比如这样
package com.mjt.factory.base;
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
/**
* Author: zhangsiqi
* Email: [email protected]
* Date: 2018/1/25
* Time: 11:09
* Desc:
*/
public class BaseResponse implements Serializable {
public BaseResponse(int ret, String message, Error error) {
this.ret = ret;
this.message = message;
this.error = error;
}
public BaseResponse(int ret, String message, T data) {
this.ret = ret;
this.message = message;
this.data = data;
}
@SerializedName("ret")
private int ret;
@SerializedName("msg")
private String message;
@SerializedName("data")
private T data;
@SerializedName("error")
private Error error;
public Error getError() {
return error;
}
public int getRet() {
return ret;
}
public String getMessage() {
return message;
}
public T getData() {
return data;
}
public static class Error {
public Error(int code, String msg) {
this.code = code;
this.msg = msg;
}
@SerializedName("code")
private int code;
@SerializedName("msg")
private String msg = "";
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
}
可以看到BaseResponse里data是object类型
但是遇到开发不规范的后台,如果object为空他会返回给你""或者"null"这样一个空字符串,这时候我们用object类型类接收就会抛一个java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING 的异常
那么怎么动态的处理这种问题呢
gson有一个TypeAdapter是可以让开发者自定义处理类型问题的
package com.mjt.common.utils.gson;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
/**
* Copyright:mjt_pad_android
* Author: liyang
* Date:2019/3/4 2:35 PM
* Desc:
*/
public class GsonTypeAdapterFactory implements TypeAdapterFactory {
@Override
public TypeAdapter create(Gson gson, TypeToken type) {
final TypeAdapter adapter = gson.getDelegateAdapter(this, type);
return new TypeAdapter() {
@Override
public void write(JsonWriter out, T value) throws IOException {
adapter.write(out, value);
}
@Override
public T read(JsonReader in) throws IOException {
try {
return adapter.read(in);
} catch (Throwable e) {
consumeAll(in);
return null;
}
}
private void consumeAll(JsonReader in) throws IOException {
if (in.hasNext()) {
JsonToken peek = in.peek();
if (peek == JsonToken.STRING) {
in.nextString();
} else if (peek == JsonToken.BEGIN_ARRAY) {
in.beginArray();
consumeAll(in);
in.endArray();
} else if (peek == JsonToken.BEGIN_OBJECT) {
in.beginObject();
consumeAll(in);
in.endObject();
} else if (peek == JsonToken.END_ARRAY) {
in.endArray();
} else if (peek == JsonToken.END_OBJECT) {
in.endObject();
} else if (peek == JsonToken.NUMBER) {
in.nextString();
} else if (peek == JsonToken.BOOLEAN) {
in.nextBoolean();
} else if (peek == JsonToken.NAME) {
in.nextName();
consumeAll(in);
} else if (peek == JsonToken.NULL) {
in.nextNull();
}
}
}
};
}
}
接下来我们来测试一下这个东西起不起作用呢
json数据正常的情况下是这样
main方法
public static void main(String[] args) {
String jsonStr="{\"name\":\"Coder\",\"friends\":{\"name\":\"庄长鹏\",\"relation\":\"好朋友\"},\"relation\":\"自己\",\"family\":[{\"name\":\"李克亮\",\"relation\":\"爸爸\"}]}";
// Gson gson=new GsonBuilder().registerTypeAdapterFactory(new GsonTypeAdapterFactory()).create();
// User json=gson.fromJson(jsonStr,User.class);
User json=new Gson().fromJson(jsonStr,User.class);
System.out.println(json);
}
User类
static class User implements Serializable{
String name;
User friends;
String relation;
List family;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User getFriends() {
return friends;
}
public void setFriends(User friends) {
this.friends = friends;
}
public List getFamily() {
return family;
}
public void setFamily(List family) {
this.family = family;
}
public String getRelation() {
return relation;
}
public void setRelation(String relation) {
this.relation = relation;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", friends=" + friends +
", relation='" + relation + '\'' +
", family=" + family +
'}';
}
}
此时的执行结果为
User{name='Coder', friends=User{name='庄长鹏', friends=null, relation='好朋友', family=null}, relation='自己', family=[User{name='李克亮', friends=null, relation='爸爸', family=null}]}
情况一
如果此时我们将jsonStr改为这样,可以看到name明明是个字符串,但是被我改为{}这样就是object类型了
public static void main(String[] args) {
String jsonStr="{\"name\":{},\"friends\":{\"name\":\"庄长鹏\",\"relation\":\"好朋友\"},\"relation\":\"自己\",\"family\":[{\"name\":\"李克亮\",\"relation\":\"爸爸\"}]}";
// Gson gson=new GsonBuilder().registerTypeAdapterFactory(new GsonTypeAdapterFactory()).create();
// User json=gson.fromJson(jsonStr,User.class);
User json=new Gson().fromJson(jsonStr,User.class);
System.out.println(json);
}
这时就进行解析就抛了异常了
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected STRING but was BEGIN_OBJECT at line 1 column 85 path $.family
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:226)
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)
情况二
我们再将jsonStr改为这样
public static void main(String[] args) {
String jsonStr="{\"name\":\"Coder\",\"friends\":\"\",\"relation\":\"自己\",\"family\":[{\"name\":\"李克亮\",\"relation\":\"爸爸\"}]}";
// Gson gson=new GsonBuilder().registerTypeAdapterFactory(new GsonTypeAdapterFactory()).create();
// User json=gson.fromJson(jsonStr,User.class);
User json=new Gson().fromJson(jsonStr,User.class);
System.out.println(json);
}
此时执行又抛异常了
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 28 path $.friends
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:226)
at com.google.gson.Gson$FutureTypeAdapter.read(Gson.java:1011)
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)
解析又出错了,因为User类中的friends是一个object类型,而jsonStr中的friends却是一个""空字符串
接下来我们使用TypeAdapter来对上述两种情况进行处理
public static void main(String[] args) {
String jsonStr="{\"name\":\"Coder\",\"friends\":\"\",\"relation\":\"自己\",\"family\":[{\"name\":\"李克亮\",\"relation\":\"爸爸\"}]}";
Gson gson=new GsonBuilder().registerTypeAdapterFactory(new GsonTypeAdapterFactory()).create();
User json=gson.fromJson(jsonStr,User.class);
// User json=new Gson().fromJson(jsonStr,User.class);
System.out.println(json);
}
执行结果为
User{name='Coder', friends=null, relation='自己', family=[User{name='李克亮', friends=null, relation='爸爸', family=null}]}
嗯 friends虽然类型不匹配,但是并不影响其他字段的解析
我们再对第一种情况进行处理
public static void main(String[] args) {
String jsonStr="{\"name\":{},\"friends\":{\"name\":\"庄长鹏\",\"relation\":\"好朋友\"},\"relation\":\"自己\",\"family\":[{\"name\":\"李克亮\",\"relation\":\"爸爸\"}]}";
Gson gson=new GsonBuilder().registerTypeAdapterFactory(new GsonTypeAdapterFactory()).create();
User json=gson.fromJson(jsonStr,User.class);
// User json=new Gson().fromJson(jsonStr,User.class);
System.out.println(json);
}
执行的结果为
User{name='null', friends=User{name='庄长鹏', friends=null, relation='好朋友', family=null}, relation='自己', family=[User{name='李克亮', friends=null, relation='爸爸', family=null}]}
嗯 json字符串中的name字段虽然变成了{}对象,但是并不影响其他字段的解析
回头我们来看看
GsonTypeAdapterFactory是怎么处理的呢
-
gson 库会通过JsonReader对json对象的每个字段进项读取,当发现类型不匹配时抛出异常
-
那么我们就在它抛出异常的时候进行处理,让它继续不中断接着往下读取其他的字段就好了
/**
* Copyright:mjt_pad_android
* Author: liyang
* Date:2019/3/4 2:35 PM
* Desc:
*/
public class GsonTypeAdapterFactory implements TypeAdapterFactory {
@Override
public TypeAdapter create(Gson gson, TypeToken type) {
final TypeAdapter adapter = gson.getDelegateAdapter(this, type);
return new TypeAdapter() {
@Override
public void write(JsonWriter out, T value) throws IOException {
adapter.write(out, value);
}
@Override
public T read(JsonReader in) throws IOException {
//gson 库会通过JsonReader对json对象的每个字段进项读取,当发现类型不匹配时抛出异常
try {
return adapter.read(in);
} catch (Throwable e) {
//那么我们就在它抛出异常的时候进行处理,让它继续不中断接着往下读取其他的字段就好了
consumeAll(in);
return null;
}
}
private void consumeAll(JsonReader in) throws IOException {
if (in.hasNext()) {
JsonToken peek = in.peek();
if (peek == JsonToken.STRING) {
in.nextString();
} else if (peek == JsonToken.BEGIN_ARRAY) {
in.beginArray();
consumeAll(in);
in.endArray();
} else if (peek == JsonToken.BEGIN_OBJECT) {
in.beginObject();
consumeAll(in);
in.endObject();
} else if (peek == JsonToken.END_ARRAY) {
in.endArray();
} else if (peek == JsonToken.END_OBJECT) {
in.endObject();
} else if (peek == JsonToken.NUMBER) {
in.nextString();
} else if (peek == JsonToken.BOOLEAN) {
in.nextBoolean();
} else if (peek == JsonToken.NAME) {
in.nextName();
consumeAll(in);
} else if (peek == JsonToken.NULL) {
in.nextNull();
}
}
}
};
}
}