您的位置:首页 > Web前端 > JavaScript

Retrofit实战之json反序列化的那些事

2016-07-22 16:30 441 查看

Retrofit实战之json反序列化的那些事

retrofit是一个十分优秀的网络框架,它为了我们封装了很多内容,使我们请求十分方便,获取也十分轻松,对于返回的json可以轻松的用gson自动解析。但是在这个方便的后面,也带来了一些小小的隐患。

下面就有两种情况,在json被反序列化时,给我们在这个炎热的夏天里造成了蛋蛋的凉意。

接口请求失败,可它还是要全部反序列化

一般来说接口返回的形式包括:返回码,信息,返回数据这三部分,大致如下:

{
statusCode: "200",
statusMessage: "回传成功",
data: {
//内容
}
}


而网络请求时,也会创建一个Response范型类,作为请求结果的映射。

public class Response <T>{

private int statusCode;
private String statusMessage;
private T data;

public int getStatusCode() {
return statusCode;
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}

public String getStatusMessage() {
return statusMessage;
}
public void setStatusMessage(String statusMessage) {
this.statusMessage = statusMessage;
}

public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}


当接口请求失败或者返回的数据错误(也就是返回码是错误码时),按照常理,我们是不会解析data的。可gson每次都会对json进行反序列化,不管json里面的数据是否是成功的,里面的data都会被反序列化。这个就有些忧伤了,我们不是应该只对成功的请求才反序列化json里面的data数据吗?

接口返回数据形式不一致

我司的接口就有这个蛋疼的问题,失败时统一返回的格式是下面这种:

{
statusCode: "103",
statusMessage: "请求失败",
data: []


只要请求失败,不管data里面的数据是JSONObject 还是JSONArray,都返回JSONArray。这就蛋疼了,经常会有json解析的异常抛出,于是我不得不含泪解决。

解决方法

基于上面的2个需求,我们得找出解决方法。由于我用retrofit都是用gson解析,所以解决这个问题的方法用的是gson特性。然后再思考一下问题的本质,其实就是它在不该反序列化的地方反序列化,导致了出错。所以我们只要找到自定义反序列化的方法就行了。

我相信很多人都用过gson,但是你真的了解它吗,其实它是很强大的,是吧,皮卡丘。对于gson不熟悉的,可以看看下面文章 你真的会用Gson吗?Gson使用指南

一般gson进行对象化映射都有两个步骤,第一步,getTypeAdapter(),第二步,read()反序列化。这在retrofit的GsonResponseBodyConverter源码中清晰可见:

//为了方便观看,我对代码进行了一些修改
public T convert(ResponseBody value) throws IOException {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}


对于TypeAdapter我们是可以自定义的,由于这里我们只需要反序列化,所以我们只用实现JsonDeserializer,并指定需要处理的类型就可以了,具体代码如下。

public class ResultJsonDeser implements JsonDeserializer<Response<?>> {

@Override
public Response<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Response response = new Response();
if (json.isJsonObject()){
JsonObject jsonObject = json.getAsJsonObject();
int code = jsonObject.get("statusCode").getAsInt();
response.setStatusCode(code);
response.setStatusMessage(jsonObject.get("statusMessage").getAsString());
if (code != 200){
return response;
}
Type itemType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
response.setData(context.deserialize(jsonObject.get("data"), itemType));
return response;
}
return response;
}
}


最后将ResultJsonDeser在gson中注册,我们就可以愉快的玩耍,不用担心那些格式的问题了。

Gson gson = new GsonBuilder()
.registerTypeHierarchyAdapter(Response.class, new ResultJsonDeser())
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.create();


当然,最后的最后,还是需要将gson加入retrofit中的,
addConverterFactory(GsonConverterFactory.create(gson))
。相信大家,对于这类问题都有一些思路了,对于retrofit的使用也能更加得劲了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息