Retrofit Gson解析空字符串的问题

编程入门 行业动态 更新时间:2024-10-13 16:16:53

Retrofit Gson解析<a href=https://www.elefans.com/category/jswz/34/1689049.html style=空字符串的问题"/>

Retrofit Gson解析空字符串的问题

在实际开发项目中,服务器经常会用空字符串 “” 作为返回结果表示空值 ,但这在Gson当中就会遇到问题,如果这项数据的类型不是字符串,Gson解析就会报错
我们希望程序可以自动将空字符串解析为对应类型的空值,比如整型就解析为0,List型就解析为一个Empty List

这个问题可以说是我用Retrofit+Gson以来最大的一个坑,以至于我在研究时差不多都要把源码看完了

提一件离奇的事是,Gson在用整型解析空字符串时,报的居然是”Inavalid double”的错误
经过研究源码后发现,Gson会优先尝试解析为整型,解析失败并不会报错误,
继续尝试解析为double型,再失败才会报错,所以得到了”Inavalid double”

解决方案:
针对整型的解析,先写一个解析适配器,实现JsonSerializer, JsonDeserializer
重写解析方法,先尝试用String类型解析,如果等于空字符串”“,则返回0值
否则再尝试用整型解析,并且catch数字格式异常转成Json解析异常抛出

public class IntegerDefault0Adapter implements JsonSerializer<Integer>, JsonDeserializer<Integer> {@Overridepublic Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {try {if (json.getAsString().equals("")){return 0;}} catch (Exception ignore){}try {return json.getAsInt();} catch (NumberFormatException e) {throw new JsonSyntaxException(e);}}@Overridepublic JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) {return new JsonPrimitive(src);}
}

然后在GsonBuilder里注册适配器到类型Integer与类型int

public static Gson buildGson() {if (gson == null) {gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").registerTypeAdapter(Integer.class, new IntegerDefault0Adapter()).registerTypeAdapter(int.class, new IntegerDefault0Adapter()).create();}return gson;}

再在构建Retrofit时用这个自定义的Gson替换掉原生的

Retrofit = new Retrofit.Builder().baseUrl(API_SERVER + "/")//传入buildGson生成的自定义Gson.addConverterFactory(GsonConverterFactory.create(buildGson())).addCallAdapterFactory(RxJavaCallAdapterFactory.create()).client(mOkHttpClient).build();

这样Gson在遇到整型解析时可以将空字符串解析为0了

然后我打算用同样的方式解决List的解析问题,但没想到情况没有这么简单。

因为List并不像整形一样是一个基本类型,List本身在数据解析的时候是要带泛型的
我不可能在构建的时候就定好集合里的数据类型。

而如果不定泛型里的数据类型,重写适配器就得根据运行时遇到的类型分别进行操作,这无异于把Gson的工作重新做一遍。

经过研究源码后发现Gson对待List也并非当做一个类型去解析的
而是在初始化时带有一个CollectionTypeAdapterFactory,在遇到JsonArray类型的数据就会调用集合类型的解析器,然后再适配集合里的对应数据类型。总之一句话就是,挺复杂,并且不怎么能扩展。

经过研究后我找到的解决方案是:

通过注解方式@JsonAdapter可以指定对应的适配器,优先级是高于默认的CollectionTypeAdapterFactory,和通过GsonBuilder传入的适配器的。
然后还是拷贝CollectionTypeAdapterFactory出来,改一份ListTypeAdapterFactory出来

/*** 列表解析类适配器的工厂类* 必须通过注解@JsonAdapter方式才能优先于默认的CollectionTypeAdapterFactory*/
public final class ListTypeAdapterFactory implements TypeAdapterFactory {public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {Type type = typeToken.getType();Class<? super T> rawType = typeToken.getRawType();if (!List.class.isAssignableFrom(rawType)) {return null;}Type elementType = $Gson$Types.getCollectionElementType(type, rawType);TypeAdapter<?> elementTypeAdapter = gson.getAdapter(TypeToken.get(elementType));@SuppressWarnings({"unchecked", "rawtypes"}) // create() doesn't define a type parameterTypeAdapter<T> result = new Adapter(gson, elementType, elementTypeAdapter);return result;}private static final class Adapter<E> extends TypeAdapter<List<E>> {private final TypeAdapter<E> elementTypeAdapter;public Adapter(Gson context, Type elementType,TypeAdapter<E> elementTypeAdapter) {this.elementTypeAdapter = new TypeAdapterRuntimeTypeWrapper<E>(context, elementTypeAdapter, elementType);}//关键部分是这里,重写解析方法public List<E> read(JsonReader in) throws IOException {//null值返回nullif (in.peek() == JsonToken.NULL) {in.nextNull();return null;}//新建一个空的列表List<E> list = new ArrayList<>();try {in.beginArray();while (in.hasNext()) {E instance = elementTypeAdapter.read(in);list.add(instance);}in.endArray();//正常解析成为列表} catch (IllegalStateException e){ //如果是空字符串,会有BEGIN_ARRAY报错//此时尝试解析成字符串,如果不是空字符串,则依旧抛出异常//如果是空字符串,则不抛出异常,使最终返回一个空的列表if (!"".equals(in.nextString())){throw e;}}return list;}public void write(JsonWriter out, List<E> list) throws IOException {if (list == null) {out.nullValue();return;}out.beginArray();for (E element : list) {elementTypeAdapter.write(out, element);}out.endArray();}}
}

最后就是Model类里面注解指定

public class UserListModel{@JsonAdapter(ListTypeAdapterFactory.class)List<UserProfileModel> users;
}

这样Gson就能将空字符串解析成为空列表了。

转自:

更多推荐

Retrofit Gson解析空字符串的问题

本文发布于:2024-02-08 21:12:22,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1675101.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:空字符串   Retrofit   Gson

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!