retrofit gson 解析json数据失败问题“com.google.gson.stream.MalformedJsonException:”

json服务端返回数据

{'success':'fail'}


retrofit 版本:2.3.0


具体问题:

com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 17 path $.forumbits[0].


问题分析:

通过把上面的json数据拿到网上在线json解析工具中进行校验,json数据校验失败。分析可能是服务器返回的数据中的单引号的问题导致解析失败,一般的json数据返回都是双引号的,gson就认为这个数据格式有问题,json数据格式不严格定义。


问题解决:

通过参考stackoverflow中的一篇文章http://stackoverflow.com/questions/27485346/malformedjsonexception-with-retrofit-api

说是要重写json转换器,本来想着直接用stackoverflow 中的代码,且找不到GsonConverter类,看来行不通了。   且看到了一句代码与错误信息中一样JsonReader.setLenient(true),通过翻译Lenient是宽松的意思,推测就是放宽json检查。



重写转换器:

先分析一下默认的GsonConverter怎么写的, 由三个类组成:

  • GsonConverterFactory // GsonConverter 工厂类, 用来创建GsonConverter
  • GsonResponseBodyConverter // 处理ResponseBody
  • GsonRequestBodyConverter // 处理RequestBody

在重写的GsonResponseBodyConverter的convert方法中添加jsonReader.setLenient(true);


具体代码如下:

public class CustomGsonConverterFactory extends Converter.Factory{
    private final Gson gson;

    public static CustomGsonConverterFactory create(){
        return create(new Gson());
    }


    private CustomGsonConverterFactory(Gson gson){
        this.gson = gson;
    }

    public static CustomGsonConverterFactory create(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        return new CustomGsonConverterFactory(gson);
    }


    @Nullable
    @Override
    public Converter, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        TypeAdapter adapter = gson.getAdapter(TypeToken.get(type));
        return new CustomGsonRequestBodyConverter<>(gson, adapter);
    }

    @Nullable
    @Override
    public Converter, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        TypeAdapter adapter = gson.getAdapter(TypeToken.get(type));
        return new CustomGsonResponseBodyConverter<>(gson, adapter);
    }
}

final class CustomGsonRequestBodyConverter<T> implements Converter<T, RequestBody> {

    private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
    private static final Charset UTF_8 = Charset.forName("UTF-8");

    private final Gson gson;
    private final TypeAdapter<T> adapter;

    CustomGsonRequestBodyConverter(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());
    }
}

final class CustomGsonResponseBodyConverter<T> implements Converter, T> {
    private final Gson gson;
    private final TypeAdapter<T> adapter;

    CustomGsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
    }

    @Override public T convert(ResponseBody value) throws IOException {
        JsonReader jsonReader = gson.newJsonReader(value.charStream());
        jsonReader.setLenient(true);
        try {
            return adapter.read(jsonReader);
        } finally {
            value.close();
        }
    }
}



你可能感兴趣的:(Android)