在项目开发中,后台返回的格式没有统一返回格式(成功和失败的返回格式不一致)。
案例说明:
登录业务json(成功时)
{
"code": 0,
"message": "登录成功",
"data": {
"name": "admin",
"token": "ad987810544564310"
}
}
登录业务json(失败时)
{
"code": 0,
"message": "登录成功",
"data": ""
}
细心的朋友可能已经发现了问题所在。成功的时候返回的Object,而失败的时候返回的String。这样就会造成json解析异常了。我们一般的配置Retrofit如下所示。
Retrofit retrofit = new Retrofit.Builder()
.client(getOkHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(BASE_URL)
.build();
GsonConverterFactory这个类解析失败,就会造成错误了。所有我们要自定义GsonConverterFactory类来解决上面的问题。
1、MyGsonConverterFactory类
public class MyGsonConverterFactory extends Converter.Factory {
public static MyGsonConverterFactory create() {
return create(new Gson());
}
@SuppressWarnings("ConstantConditions") // Guarding public API nullability.
public static MyGsonConverterFactory create(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
return new MyGsonConverterFactory(gson);
}
private final Gson gson;
private MyGsonConverterFactory(Gson gson) {
this.gson = gson;
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new MyGsonResponseBodyConverter<>(gson, adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new MyGsonRequestBodyConverter<>(gson, adapter);
}
}
2、MyGsonRequestBodyConverter类
public class MyGsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType.get("application/json; charset=UTF-8");
private static final Charset UTF_8 = Charset.forName("UTF-8");
private final Gson gson;
private final TypeAdapter<T> adapter;
MyGsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override public RequestBody convert(T value) throws IOException {
Buffer buffer = new Buffer();
Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
JsonWriter jsonWriter = gson.newJsonWriter(writer);
adapter.write(jsonWriter, value);
jsonWriter.close();
return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
}
}
3、MyGsonResponseBodyConverter类
public class MyGsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
MyGsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override
public T convert(ResponseBody value) throws IOException {
String json = value.string();
//第一次解析
BaseBean obj = GsonUtils.json2Bean(json, BaseBean.class);
if (!obj.isSuccess()) {
//如果是服务端返回的错误码,则抛出自定义异常
throw new ApiException(obj.getStatus(), obj.getMsg());
}
//第二次解析
T result = adapter.fromJson(json);
value.close();
return result;
//原生的代码(RxJava中的代码)
// JsonReader jsonReader = gson.newJsonReader(value.charStream());
// try {
// T result = adapter.read(jsonReader);
// if (jsonReader.peek() != JsonToken.END_DOCUMENT) {
// throw new JsonIOException("JSON document was not fully consumed.");
// }
// return result;
// } finally {
// value.close();
// }
}
}
调用方式
Retrofit retrofit = new Retrofit.Builder()
.client(getOkHttpClient())
// .addConverterFactory(GsonConverterFactory.create()) //替换调之前的,采用下面的方式即可
.addConverterFactory(MyGsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(BASE_URL)
.build();
另外附上json解析工具类:
public class GsonUtils {
private static Gson mGson = new Gson();
public static <T> T json2Bean(String json, Class<T> clazz) {
try {
return mGson.fromJson(json, clazz);
} catch (Exception e) {
LogUtils.e("GsonUtils:"+e.toString());
return null;
}
}
}