<
Retrofit修改接口返回数据
>
上一篇

解决github等clone慢的问题
下一篇

关闭win迅雷极速版自动升级

根据json格式规范,一个json对象,空的时候应返回null而不是返回字符串类型,内容空则应返回{}.

先看问题:

理想的规范返回字段data:null

{
code:-101
msg:"token已过期"
data:null
}

不规范的返回字段data:""

{
code:-101
msg:"token已过期"
data:""
}

返回字段不固定, Android这边利用Gson等直接转换指定JavaBean就会出现类型转换异常了


解决方案一, 从Retrofit的Converter入手:

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


解决方案二, 从Gson解析过程入手, 在GsonConverterFactory构建过程处理:

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

Top
Foot