根据json格式规范,一个json对象,空的时候应返回null而不是返回字符串类型,内容空则应返回{}.
先看问题:
理想的规范返回字段data:null
{
code:-101
msg:"token已过期"
data:null
}
不规范的返回字段data:""
{
code:-101
msg:"token已过期"
data:""
}
返回字段不固定, Android这边利用Gson等直接转换指定JavaBean就会出现类型转换异常了
public class CustomConverterFactory extends Converter.Factory {
private final Gson gson;
public static CustomConverterFactory create() {
return create(new Gson());
}
@SuppressWarnings("ConstantConditions")
public static CustomConverterFactory create(Gson gson) {
if (gson == null) {
throw new NullPointerException("gson == null");
}
return new CustomConverterFactory(gson);
}
private CustomConverterFactory(Gson gson) {
this.gson = gson;
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
//这里是自定义响应Converter
return new CustomResponseConverter<>(gson, adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
//这里是自定义请求Converter
return new CustomRequestConverter<>(gson, adapter);
}
}
/**
* copy form retrofit2.converter.gson.GsonRequestBodyConverter
*/
class CustomRequestConverter<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;
CustomRequestConverter(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());
}
}
class CustomResponseConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
CustomResponseConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Nullable
@Override
public T convert(ResponseBody value) throws IOException {
try {
String originalBody = value.string();
JSONObject json = new JSONObject(originalBody);
//后端返回data默认值"" 需要处理
Object data = json.opt("data");
//com.google.gson.JsonObject 解析data:""会解析成字符串"\"\"" 而org.json.JSONObject将会解析成空字符串""
if (data == null || ("".equals(data.toString().trim()) || "\"\"".equals(data.toString().trim()))) {
json.put("data", null);
}
return adapter.fromJson(json.toString());
} catch (JSONException e) {
throw new RuntimeException(e.getMessage());
} finally {
value.close();
}
}
}
Retrofit retrofit = new Retrofit.Builder()
//此处使用
.addConverterFactory(CustomConverterFactory.create())
//others
//...
.build();
OK
public class ResponseBodyDefault implements JsonDeserializer<BaseBean<?>> {
@Override
public BaseBean<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
BaseBean response = new BaseBean();
if (json.isJsonObject()) {
JsonObject jsonObject = json.getAsJsonObject();
int code = jsonObject.get("code").getAsInt();
response.setErrorCode(code);
String msg = jsonObject.get("msg").getAsString();
response.setMsg(msg);
//处理data字段
JsonElement data = jsonObject.get("data");
if (data != null) {
//com.google.gson.JsonObject 解析data:""会解析成字符串"\"\"" 而org.json.JSONObject将会解析成空字符串""
if (data.isJsonPrimitive() && ("".equals(data.toString().trim()) || "\"\"".equals(data.toString().trim()))) {
response.setData(null);
} else {
response.setBody(context.deserialize(data, ((ParameterizedType) typeOfT).getActualTypeArguments()[0]));
}
}
return response;
}
return response;
}
}
这里BaseBean是接口返回的数据的基本结构JavaBean, 自己的返回类型, data用Object或泛型
Retrofit retrofit = new Retrofit.Builder()
//此处使用
.addConverterFactory(GsonConverterFactory.create(new GsonBuilder()
//此处使用
.registerTypeHierarchyAdapter(BaseBean.class, new ResponseBodyDefault())
.create()))
//others
//...
.build();
OK