记得有次面试,面试官问了这么一个问题。如果服务器端返回的某个字段有的时候可能是一个int 有的时候是个String 有的时候是个数组怎么处理。(当时一脸懵逼)就说改啊~ 好吧,你回去等通知吧。。GG..
在日常开发中,服务器端有可能将一个字段返回多种内容,有可能是在不同环境下出现的这种情况,也有可能设定的为这种情况要怎么处理呢。其实Gson的一个用法就可以满足这种需求,下面我们看一下要处理的Json数据:
情况1:data为空
{
"data":"",
"code":1,
"message":"请求失败"
}
情况2:data为null
{
"data":null,
"code":1,
"message":"请求失败"
}
情况3:data为对象类型
{
"data":{
"name":"郝建",
"phone":"13900000000"
},
"code":0,
"message":"请求成功"
}
情况4:data为集合类型
{
"data":[
{
"name":"李白",
"phone":"13888888888"
},
{
"name":"李黑",
"phone":"13855555555"
}
],
"code":0,
"message":"请求成功"
}
情况5:data的值为字符串,解析时需要去除转义字符拿到具体的对象
{
"data":"{"id":9876,"title":"标题0010","content":"","url":"http://www.baidu.com"}",
"code":0,
"message":"请求成功"
}
情况6:data的值为字符串,解析时需要去除转义字符拿到具体的集合对象
{
"data":"[{"id":6543,"title":"标题0002","content":"","url":"http://www.sina.com"},{"id":3210,"title":"title6543","content":"","url":""}]",
"code":0,
"message":"请求成功"
}
通常一个接口都有一个共同的地方就是code 和 message字段
所以可以定一个data的泛型基础类如下:
public class ResultData {
public T data;
public int code;
public String message;
/**
* 扩展字段
* 0:data为对象
* 1:data为集合
* 2:date为空或者null字段
*/
public int dataType;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getDataType() {
return dataType;
}
public void setDataType(int dataType) {
this.dataType = dataType;
}
@Override
public String toString() {
return "{" +
"data=" + data +
", code=" + code +
", message='" + message + '\'' +
", dataType=" + dataType +
'}';
}
}
定义完了基础类,就要进入我们的重点了,就是自定义解析器,接口重写 deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) 方法,并进行处理。
public class MyFormatParser implements JsonDeserializer {
private Class mClass;
public MyFormatParser(Class tClass) {
this.mClass = tClass;
}
@Override
public ResultData deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
JsonObject mJsonObject = json.getAsJsonObject();
ResultData mResult = new ResultData();
String mJson = mJsonObject.get("data").toString();
//情况3:data为对象类型
if (mJsonObject.get("data").isJsonObject() &&
!mJsonObject.get("data").isJsonNull()) {
mResult.setData(fromJsonObject(mJson, mClass));
mResult.setDataType(0);
} else if (mJsonObject.get("data").isJsonArray() && !mJsonObject.get("data").isJsonNull()) {
//情况4:data为集合类型
mResult.setData(fromJsonArray(mJson, mClass));
mResult.setDataType(1);
} else if (mJsonObject.get("data").isJsonPrimitive() &&
!mJsonObject.get("data").isJsonNull()) {
// 服务端返回data的值为"{}","[]",将对象或者集合以字符串的形式返回回来,
// 先去除两边的双引号,再去掉转义字符
String mNewJson = mJson.substring(1, mJson.length() - 1).replaceAll("\\\\", "");
// 根据处理好的Json字符串判断是集合还是对象,再进行解析。
//情况6:data的值为字符串,解析时需要去除转义字符拿到具体的集合对象
if (mNewJson.startsWith("[") || mNewJson.endsWith("]")) {
mResult.setData(fromJsonArray(mNewJson, mClass));
mResult.setDataType(1);
} else if (mNewJson.startsWith("{") || mNewJson.endsWith("}")) {
//情况5:data的值为字符串,解析时需要去除转义字符拿到具体的对象
mResult.setData(fromJsonObject(mNewJson, mClass));
mResult.setDataType(0);
} else {
mResult.setData(fromJsonObject(mResult.toString(), mClass));
mResult.setDataType(2);
}
} else if (mJsonObject.get("data").isJsonNull() || mJsonObject.get("data").getAsString().isEmpty()) {
//第一种和第二种情况
mResult.setData(fromJsonObject(mResult.toString(), mClass));
mResult.setDataType(2);
}
// 返回的状态码。
mResult.setCode(mJsonObject.get("code").getAsInt());
// 返回的状态信息。
mResult.setMessage(mJsonObject.get("message").getAsString());
return mResult;
}
/**
* 用来解析集合
*/
private ArrayList fromJsonArray(String json, Class clazz) {
Type type = new TypeToken>() {
}.getType();
ArrayList jsonObjects = new Gson().fromJson(json, type);
ArrayList arrayList = new ArrayList<>();
for (JsonObject jsonObject : jsonObjects) {
arrayList.add(new Gson().fromJson(jsonObject, clazz));
}
return arrayList;
}
/**
* 用来解析对象
*/
private T fromJsonObject(String json, Class type) {
return new Gson().fromJson(json, type);
}
}
有了基础类,有了实体,接下来就可以封装一个GsonBuilder的配置类
public class FromJsonUtils {
public static ResultData fromJson(String json,Class mClass){
/* Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation() //不导出实体中没有用@Expose注解的属性
.enableComplexMapKeySerialization() //支持Map的key为复杂对象的形式
.serializeNulls().setDateFormat("yyyy-MM-dd HH:mm:ss:SSS")//时间转化为特定格式
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)//会把字段首字母大写,注:对于实体上使用了@SerializedName注解的不会生效.
.setPrettyPrinting() //对json结果格式化.
.setVersion(1.0) //有的字段不是一开始就有的,会随着版本的升级添加进来,那么在进行序列化和返序列化的时候就会根据版本号来选择是否要序列化.
//@Since(版本号)能完美地实现这个功能.还的字段可能,随着版本的升级而删除,那么
//@Until(版本号)也能实现这个功能,GsonBuilder.setVersion(double)方法需要调用.
.create();*/
return new GsonBuilder()
//为特定对象设置固定的序列和反序列方式,实现JsonSerializer和JsonDeserializer接口
.registerTypeAdapter(ResultData.class,new MyFormatParser(mClass))
.enableComplexMapKeySerialization() //支持Map的key为复杂对象的形式
.serializeNulls() //输出为null时的字段
.create()
.fromJson(json,ResultData.class);
}
}
我们在写两个测试用的Bean类
public class DataBean {
public String name;
public String phone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
public class UIBean {
private int id;
private String title;
private String content;
private String url;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
最后测试我们的这些类
public class JsonGsonActivity extends AppCompatActivity {
private static final String mJson1 =
"{\"data\": \"\", \"code\": 1, \"message\": \"请求失败\"}";
private static final String mJson2 =
"{\"data\": null, \"code\": 1, \"message\": \"请求失败\"}";
private static final String mJson3 =
"{\"data\": {\"name\": \"郝建\", \"phone\": \"13900000000\"}, \"code\": 0, \"message\": \"请求成功\"}";
private static final String mJson4 =
"{\"data\": [{\"name\": \"李白\", \"phone\": \"13888888888\"},{\"name\": \"李黑\", \"phone\": \"13855555555\"}],\"code\": 0, \"message\": \"请求成功\"}";
private static final String mJson5 =
"{\"data\":\"{\\\"id\\\":9876,\\\"title\\\":\\\"标题0010\\\",\\\"content\\\":\\\"\\\",\\\"url\\\":\\\"http://www.baidu.com\\\"}\",\"code\":0,\"message\":\"请求成功\"}";
private static final String mJson6 =
"{\"data\":\"[{\\\"id\\\":6543,\\\"title\\\":\\\"标题0002\\\",\\\"content\\\":\\\"\\\",\\\"url\\\":\\\"http://www.sina.com\\\"},{\\\"id\\\":3210,\\\"title\\\":\\\"title6543\\\",\\\"content\\\":\\\"\\\",\\\"url\\\":\\\"\\\"}]\",\"code\":0,\"message\":\"请求成功\"}";
private TextView tv01;
private TextView tv02;
private TextView tv03;
private TextView tv04;
private TextView tv05;
private TextView tv06;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
tv01 = (TextView) findViewById(R.id.tv_01);
tv02 = (TextView)findViewById(R.id.tv_02);
tv03 = (TextView) findViewById(R.id.tv_03);
tv04 = (TextView) findViewById(R.id.tv_04);
tv05 = (TextView) findViewById(R.id.tv_05);
tv06 = (TextView) findViewById(R.id.tv_06);
ResultData mData1 = FromJsonUtils.fromJson(mJson1, DataBean.class);
tv01.setText("解析后取值:" + mData1.getData().getName() +" 数据类型:" + mData1.getDataType());
ResultData mData2 = FromJsonUtils.fromJson(mJson2, DataBean.class);
tv02.setText("解析后取值:" + mData2.getData().getName() +" 数据类型:" + mData2.getDataType());
ResultData mData3 = FromJsonUtils.fromJson(mJson3, DataBean.class);
tv03.setText("解析后取值:" + mData3.getData().getName() +" 数据类型:" + mData3.getDataType());
ResultData> mData4 = FromJsonUtils.fromJson(mJson4, DataBean.class);
StringBuffer stringBuffer=new StringBuffer();
for (DataBean mData : mData4.getData()) {
stringBuffer.append("解析后取值:" + mData.getName() +" 数据类型:" + mData4.getDataType());
}
tv04.setText(stringBuffer);
ResultData mData5 = FromJsonUtils.fromJson(mJson5, UIBean.class);
tv05.setText("解析后取值:" + mData5.getData().getTitle() +" 数据类型:" + mData5.getDataType());
StringBuffer stringBuffer1 = new StringBuffer();
ResultData> mData6 = FromJsonUtils.fromJson(mJson6, UIBean.class);
for (UIBean mActivity : mData6.getData()) {
stringBuffer1.append("解析后取值:" + mActivity.getTitle() +" 数据类型:" + mData6.getDataType());
}
tv06.setText(stringBuffer1);
}
}