改编自:
https://codeday.me/bug/20190220/651618.html
我正在使用Retrofit(与OkHttp和GSON组合)与在线网络服务进行通信.
webservice包含了所有响应的默认包装,类似于:
{
"resultCode":"OK",
"resultObj":"Can be a string or JSON object / array",
"error":"",
"message":""
}
在此示例中,resultCode将为OK或NO.此外,当处理请求时发生错误时,错误和消息只有任何内容.最后,但并非最不重要的是,resultObj将包含调用的实际结果(该示例中是一个字符串,但有些调用返回一个JSON数组或一个JSON对象).
要处理这个元数据,我创建了一个泛型类,像这样:
public class ApiResult<T> {
private String error;
private String message;
private String resultCode;
private T resultObj;
// + some getters, setters etcetera
}
我还创建了代表有时在resultObj中给出的响应的类,并且我已经定义了一个用于Retrofit的接口,看起来有点像这样:
public interface SomeWebService {
@GET("/method/string")
ApiResult<String> someCallThatReturnsAString();
@GET("/method/pojo")
ApiResult<SomeMappedResult> someCallThatReturnsAnObject();
}
只要请求有效,这一切都正常.但是当服务器端发生错误时,它仍然会返回一个String类型的resultObj.这会导致SomeCallThatReturnsAnObject在Retrofit RestAdapter / GSON库中崩溃,并显示如下消息:
retrofit.RetrofitError:
com.google.gson.JsonSyntaxException:
java.lang.IllegalStateException:
Expected BEGIN_OBJECT but was STRING at line 1 column 110 path $.resultObj
现在,最后我的问题是:
有没有(容易的)告诉GSON,如果它不符合预期的类型,它应该忽略(也就是“取消”)一个属性?
我可以告诉GSON将空字符串视为null吗?
答案:
像这样定义你的模型:
public class ApiResult {
private String error;
private String message;
private String resultCode;
private MyResultObject resultObj;
}
然后,为MyResultObject创建一个TypeAdapterFactory:
/**
* https://codeday.me/bug/20190220/651618.html
* */
public static class FindStringAndConvertToNullAdapterFactory implements TypeAdapterFactory {
@Override
@SuppressWarnings("unchecked")
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
if (type.getRawType() == MyResultObject.class) {
TypeAdapter<MyResultObject> defaultAdapter = (TypeAdapter<MyResultObject>) gson.getDelegateAdapter(this, type);
return (TypeAdapter<T>) new FindStringAndConvertToNullAdapter(defaultAdapter);
} else {
return null;
}
}
public class FindStringAndConvertToNullAdapter<T> extends TypeAdapter<T> {
protected TypeAdapter<T> defaultAdapter;
public FindStringAndConvertToNullAdapter(TypeAdapter<T> defaultAdapter) {
this.defaultAdapter = defaultAdapter;
}
@Override
public void write(JsonWriter out, T value) throws IOException {
defaultAdapter.write(out, value);
}
@Override
public T read(JsonReader in) throws IOException {
/*
This is the critical part. So if the value is a string,
Skip it (no exception) and return null.
*/
if (in.peek() == JsonToken.STRING) {
in.skipValue();
return null;
}
return defaultAdapter.read(in);
}
}
}
最后,为Gson注册MyResultObjectAdapterFactory:
gson = new GsonBuilder()
.registerTypeAdapterFactory(new FindStringAndConvertToNullAdapterFactory())
.create();
现在,当使用该Gson对象反序列化一个ApiResult json时,如果它是一个字符串,那么resultObj将被设置为null.
我希望这能解决你的问题=)
网友评论