由于之前跟服务器那边没有很好的沟通,导致这个问题到了后期服务器也不好修改了。
项目中使用的是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, RequestBody> 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。
本人才疏学浅,有不当的地方还请多多指教。