Gson解析异常 Expected BEGIN_ARRAY but was BEGIN_OBJECT

 

 

由于之前跟服务器那边没有很好的沟通,导致这个问题到了后期服务器也不好修改了。

项目中使用的是rxjava + retrofit2,发生这个错误 java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 34 path 主要是 在返回结构体中声明的是 list 集合, 但是由于项目初期没有跟服务器协商好,当列表结构没有数据的时候应当返回个空数组,但是却返回了一个object的对象,这时候 gson就会解析出错。


        @POST("api/v2_3_2/group/quee")
        @FormUrlEncoded
        Observable>> getCircleScrollInfo(@FieldMap Map map);

ApiResponseBean是统一外层model

public class ApiResponseBean {

    @SerializedName("status") private int status;
    @SerializedName("errorCode")
    private String errorCode;
    
    @SerializedName("result")
    private T result;
    
    @SerializedName("message")
    private String message;

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }

    public T getResult() {
        return result;
    }

    public void setResult(T result) {
        this.result = result;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public boolean isSuccess() {
        return status == 1;
    }

}

泛型T就会解析失败。

这时候我们就需要在构造Retrofit 的时候 给gson加入接管List的解析规则

retrofit = new Retrofit.Builder()
                            .baseUrl(Constant.Url.DEBUG_153)
                            .addConverterFactory(CustomGsonConverterFactory.create())
                            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                            .client(client)
                            .build();

CustomGsonConverterFactory.class

public class CustomGsonConverterFactory extends Converter.Factory {

    public static CustomGsonConverterFactory create() {
        return create(new GsonBuilder()
                .registerTypeAdapter(Integer.class, new IntegerTypeAdapter())
                .registerTypeAdapter(Double.class, new DoubleTypeAdapter())
                .registerTypeAdapterFactory(DataTypeAdaptor.FACTORY)
                //解决服务器接口设计时没有保证数据的一致性
                .registerTypeHierarchyAdapter(List.class, new JsonDeserializer>() {
                    @Override
                    public List deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                        if (json.isJsonArray()) {
                            JsonArray array = json.getAsJsonArray();
                            Type itemType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
                            List list = new ArrayList<>();
                            for (int i = 0; i < array.size(); i++) {
                                JsonElement element = array.get(i);
                                Object item = context.deserialize(element, itemType);
                                list.add(item);
                            }
                            return list;
                        } else {
                            //和接口类型不符,返回空List
                            return Collections.EMPTY_LIST;
                        }
                    }
                })
                .create());
    }

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

    private final Gson gson;

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

    @Override
    public Converter responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        return new CustomGsonResponseBodyConverter<>(gson,type);
    }

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

CustomGsonResponseBodyConverter.class

public class CustomGsonResponseBodyConverter implements Converter {
    private Gson gson;
    private Type type;

    public CustomGsonResponseBodyConverter(Gson gson, Type type) {
        this.gson = gson;
        this.type = type;
    }

    @Override
    public T convert(ResponseBody value) throws IOException {
        String response = value.string();
        try {
           //todo 

           
            return gson.fromJson(response, type);

        } finally {
            value.close();
        }
    }


}

这样就可以解决问题了。关键点在于:

//解决服务器接口设计时没有保证数据的一致性
                .registerTypeHierarchyAdapter(List.class, new JsonDeserializer>() {
                    @Override
                    public List deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                        if (json.isJsonArray()) {
                            JsonArray array = json.getAsJsonArray();
                            Type itemType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
                            List list = new ArrayList<>();
                            for (int i = 0; i < array.size(); i++) {
                                JsonElement element = array.get(i);
                                Object item = context.deserialize(element, itemType);
                                list.add(item);
                            }
                            return list;
                        } else {
                            return Collections.EMPTY_LIST;
                        }
                    }
                })

插入一个问题,当我们在model中声明某个字段为double,int的时候,如果服务器返回的数据中 这个字段为 空字符串的时候,同样也会解析失败报错,NumberFormatException

其实gson可以让我们自定义解析器这里我就不详细介绍gson的用法了,附上个比较详细的博文供大家学习

你真的会用Gson吗?Gson使用指南

在构造Gson的时候加入解析适配器

new GsonBuilder()
                .registerTypeAdapter(Integer.class, new IntegerTypeAdapter())
                .registerTypeAdapter(Double.class, new DoubleTypeAdapter())

public class IntegerTypeAdapter extends TypeAdapter {

    @Override
    public void write(JsonWriter out, Integer value) throws IOException {
        out.value(String.valueOf(value));
    }

    @Override
    public Integer read(JsonReader in) throws IOException {
        String numberStr = in.nextString();
        return StringUtil.toInt(numberStr);
    }
}
public class DoubleTypeAdapter extends TypeAdapter {

    @Override
    public void write(JsonWriter out, Double value) throws IOException {
        out.value(String.valueOf(value));
    }

    @Override
    public Double read(JsonReader in) throws IOException {
        return StringUtil.toDouble(in.nextString());
    }
}

end。

本人才疏学浅,有不当的地方还请多多指教。

你可能感兴趣的:(android)