在我做的项目中,服务器经常会用空字符串 “” 作为返回结果表示空值
但这在Gson当中就会遇到问题,如果这项数据的类型不是字符串,Gson解析就会报错
我们希望程序可以自动将空字符串解析为对应类型的空值,比如整型就解析为0,List型就解析为一个Empty List
这个问题可以说是我用Retrofit+Gson以来最大的一个坑,以至于我在研究时差不多都要把源码看完了
提一件离奇的事是,Gson在用整型解析空字符串时,报的居然是”Inavalid double”的错误
经过研究源码后发现,Gson会优先尝试解析为整型,解析失败并不会报错误,
继续尝试解析为double型,再失败才会报错,所以得到了”Inavalid double”
解决方案:
针对整型的解析,先写一个解析适配器,实现JsonSerializer<Integer>, JsonDeserializer<Integer>
重写解析方法,先尝试用String类型解析,如果等于空字符串””,则返回0值
否则再尝试用整型解析,并且catch数字格式异常转成Json解析异常抛出
|
|
然后在GsonBuilder里注册适配器到类型Integer与类型int
|
|
再在构建Retrofit时用这个自定义的Gson替换掉原生的
|
|
这样Gson在遇到整型解析时可以将空字符串解析为0了
然后我打算用同样的方式解决List的解析问题,但没想到情况没有这么简单。
因为List并不像整形一样是一个基本类型,List本身在数据解析的时候是要带泛型的
我不可能在构建的时候就定好集合里的数据类型。
而如果不定泛型里的数据类型,重写适配器就得根据运行时遇到的类型分别进行操作,这无异于把Gson的工作重新做一遍。
并且经过研究源码后发现Gson对待List也并非当做一个类型去解析的
而是在初始化时带有一个CollectionTypeAdapterFactory,在遇到JsonArray类型的数据就会调用集合类型的解析器,然后再适配集合里的对应数据类型。总之一句话就是,挺复杂,并且不怎么能扩展。
经过研究后我找到的解决方案是
通过注解方式@JsonAdapter可以指定对应的适配器,优先级是高于默认的CollectionTypeAdapterFactory,和通过GsonBuilder传入的适配器的。
然后还是拷贝CollectionTypeAdapterFactory出来,改一份ListTypeAdapterFactory出来
|
|
最后就是Model类里面注解指定
|
|
这样Gson就能将空字符串解析成为空列表了。