我正在使用Retrofit(与OkHttp和GSON结合使用)与在线Web服务进行通信。该Web服务的所有响应都有一个默认包装,类似于:
{ "resultCode":"OK", "resultObj":"Can be a string or JSON object / array", "error":"", "message":"" }
在此示例中,resultCode将为OK或NO。此外error,message仅在处理请求时发生错误时才包含任何内容。最后但并非最不重要的一点,resultObj将包含调用的实际结果(示例中为字符串,但是某些调用返回JSON数组或JSON对象)。
resultCode
OK
NO
error
message
resultObj
为了处理此元数据,我创建了一个通用类,如下所示:
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(); }
只要请求有效,所有这些都可以正常工作。但是,当服务器端发生错误时,它仍然会返回resultObjString类型的。这会导致someCallThatReturnsAnObjectRetrofit RestAdapter / GSON库内部崩溃,并显示以下消息:
someCallThatReturnsAnObject
retrofit.RetrofitError:com.google.gson.JsonSyntaxException:java.lang.IllegalStateException: 预期为BEGIN_OBJECT,但位于第1行第110列的路径$ .resultObj
retrofit.RetrofitError:com.google.gson.JsonSyntaxException:java.lang.IllegalStateException:
预期为BEGIN_OBJECT,但位于第1行第110列的路径$ .resultObj
现在,最后,我的问题是:
像这样定义模型:
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 是 string ,则将其设置为 null 。 * __
我希望这可以解决您的问题=)