我正在使用Retrofit(与OkHttp和GSON组合)与在线网络服务进行通信.
webservice包含了所有响应的默认包装,类似于:
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:
public class MyResultObjectAdapterFactory implements TypeAdapterFactory { @Override @SuppressWarnings("unchecked") public <T> TypeAdapter<T> create(Gson gson,TypeToken<T> type) { if (type.getRawType()!= MyResultObject.class) return null; TypeAdapter<MyResultObject> defaultAdapter = (TypeAdapter<MyResultObject>) gson.getDelegateAdapter(this,type); return (TypeAdapter<T>) new MyResultObjectAdapter(defaultAdapter); } public class MyResultObjectAdapter extends TypeAdapter<MyResultObject> { protected TypeAdapter<MyResultObject> defaultAdapter; public MyResultObjectAdapter(TypeAdapter<MyResultObject> defaultAdapter) { this.defaultAdapter = defaultAdapter; } @Override public void write(JsonWriter out,MyResultObject value) throws IOException { defaultAdapter.write(out,value); } @Override public MyResultObject 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 gson = new GsonBuilder() .registerTypeAdapterFactory(new MyResultObjectAdapterFactory()) .create();
现在,当使用该Gson对象反序列化一个ApiResult json时,如果它是一个字符串,那么resultObj将被设置为null.
我希望这能解决你的问题=)