`
wx1569110409
  • 浏览: 20571 次
文章分类
社区版块
存档分类
最新评论

Retrofit+RxJava实战日志(4)-Gson解析空字符串的问题

 
阅读更多

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

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

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

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

public class IntegerDefault0Adapter implements JsonSerializer<Integer>, JsonDeserializer<Integer> {
    @Override    public 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);
        }
    }

    @Override    public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) {        return new JsonPrimitive(src);
    }
}

 

 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

然后在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;
   }

 

 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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

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

 

 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这样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 parameter
        TypeAdapter<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值返回null
            if (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();
        }
    }
}

 

 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

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

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

 

 
 
 
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

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

转载于:https://my.oschina.net/Denniswang/blog/662040

分享到:
评论

相关推荐

    基于Kotlin +MVP+Retrofit+RxJava+Glide等架构实现短视频类小项目.zip

    基于Kotlin +MVP+Retrofit+RxJava+Glide等架构实现短视频类小项目基于Kotlin +MVP+Retrofit+RxJava+Glide等架构实现短视频类小项目基于Kotlin +MVP+Retrofit+RxJava+Glide等架构实现短视频类小项目基于Kotlin +MVP+...

    Retrofit2+Rxjava2+MVP demo

    Retrofit支持GET、POST、PUT等多种HTTP请求方法,并且可以方便地处理JSON数据,通过Gson或Jackson等库将JSON字符串自动转化为Java对象。 【RxJava2】 RxJava是一个在Java VM上使用 Reactive Extensions 的库,它...

    Retrofit+rxjava+mvp形式上传多张图片完整示例

    总结来说,这个示例提供了一个完整的Android应用实现,包括图片选择、Retrofit+RxJava的图片上传以及MVP架构的应用,对于学习和实践Android网络编程和响应式编程具有很高的参考价值。理解并掌握这些技术,将有助于...

    最新retrofit+rxjava+MVP

    总的来说,"最新retrofit+rxjava+MVP"是一个现代化的Android开发架构,它利用Retrofit简化网络通信,通过RxJava实现异步操作的优雅处理,借助MVP模式提升代码组织和测试性。开发者在实践中可以灵活运用这些工具,...

    Retrofit+RXJava+MVP

    在Android开发中,Retrofit、RXJava和MVP(Model-View-Presenter)是三个非常重要的库和技术模式,它们能够帮助开发者构建出高效、可维护的网络请求与应用架构。让我们详细了解一下这三个技术。 首先,Retrofit是由...

    Android retrofit+rxjava+okhttp 学习案例

    在Android开发中,Retrofit、RxJava和OkHttp...总的来说,"Android retrofit+rxjava+okhttp"的学习对于Android开发者来说是提高生产力的重要步骤。通过深入理解和实践,可以大大提升网络请求部分的代码质量和可维护性。

    一步步搭建Retrofit+RxJava+MVP网络请求框架

    一步步搭建Retrofit+RxJava+MVP网络请求框架 完整的代码

    Retrofit+RxJava封装网络请求

    总结,Retrofit+RxJava的组合为Android开发提供了强大的网络请求和文件下载能力。通过Retrofit的接口定义和RxJava的流控制,我们可以轻松实现异步操作,同时保持代码的整洁和可维护性。正确地使用这两个库,能够极大...

    rxjava+retrofit+okhttp实现网络请求

    在Android开发中,网络请求是不可或缺的一部分,而`RxJava`、`Retrofit`和`OkHttp`的组合成为了一种高效、灵活的解决方案。这三个库各司其职,共同构建了一个强大的网络请求框架。 首先,`Retrofit`是由Square公司...

    Rxjava+ReTrofit+okHttp深入浅出-终极封装

    1.Retrofit+Rxjava+okhttp基本使用方法 2.统一处理请求数据格式 3.统一的ProgressDialog和回调Subscriber处理 4.取消http请求 5.预处理http请求 6.返回数据的统一判断 7.失败后的retry处理 具体思路参考博客:...

    基于OkHttp+Retrofit+Rxjava组合的高性能、超解耦、动态处理链式请求、单例模式的网络框架源码+文档说明.zip

    基于OkHttp+Retrofit+Rxjava组合的高性能、超解耦、动态处理、链式请求、单例模式的网络框架源码+文档说明.zip基于OkHttp+Retrofit+Rxjava组合的高性能、超解耦、动态处理、链式请求、单例模式的网络框架源码+文档...

    retrofit+rxjava+MVP框架的使用

    同时,Model层也可能包含数据解析逻辑,如使用Gson或其它库将JSON字符串转化为Java对象。 2. **Presenter层**:订阅Retrofit返回的Observable,处理业务逻辑,比如对数据进行过滤、排序等。Presenter调用Model的接口...

    Material Design + MVP + RxJava2 + Retrofit + Dagger2 + Realm + Glide + Kotlin

    初始化的简单的app架构,基于Kotlin+ Material Design + MVP + RxJava2 + Retrofit + Dagger2 + Realm + Glide 使用RxJava配合Retrofit2做网络请求 使用RxUtil对线程操作和网络请求结果处理做了封装 使用...

    Kotlin版本的retrofit+rxjava 重磅来袭,关于什么是retrofit+rxjava,是做

    # 一、Kotlin版本的retrofit+rxjava ## 简介 重磅来袭,关于什么是retrofit+rxjava,是做什么的,有什么优势,还有应该怎么学习,这里我就不多说,不懂的你们先去搜索有关资料,这里只介绍怎么使用和封装 废话不多...

    安卓retrofit2 + rxjava2 + okhttp3多线程下载

    本项目标题提到的"安卓retrofit2 + rxjava2 + okhttp3多线程下载"正是一个利用现代Android开发库来优化下载流程的方法。以下将详细介绍这三个库以及它们如何协同工作实现多线程下载。 1. **Retrofit2**: Retrofit...

    okhttp-3.4.1,okio-1.10+retrofit-2.1.0+rxjava-2.0.1+RxAndroid+gson-2.1.0

    Retrofit 2.1.0 提供了对Gson、Jackson等多种序列化库的支持,简化了JSON数据的解析。 4. **RxJava-2.0.1**: RxJava 是一个反应式编程库,它将异步数据流转换为可观察的序列,从而简化多线程和事件处理。RxJava ...

    RxJava+Retrofit+okhttp上传图片给后台

    4. **使用RxJava调用Retrofit服务**:创建Retrofit实例,然后订阅并执行上传方法。 ```java Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://your-server-url.com/") .addConverterFactory...

    Android中MVP+Retrofit+Rxjava框架的demo

    总结起来,这个"Android中MVP+Retrofit+Rxjava框架的demo"是一个很好的学习资源,可以帮助开发者掌握如何在Android应用中实施高效、模块化的架构,以及如何利用现代网络和响应式编程工具进行数据处理。通过研究这个...

    Okhttp+Retrofit+Rxjava+Picasso

    在Android开发中,"Okhttp+Retrofit+Rxjava+Picasso"是一个常见的高效网络请求与数据处理的组合。这个组合充分利用了各自库的优势,构建了一个强大、灵活且易于管理的网络请求架构。 首先,OkHttp是Square公司推出...

    Retrofit2+Rxjava2+Rxandroid+okhttp3+Lifecycle 的MVP网络框架,精简Google官方AAC框架

    本框架使用Retrofit2+Rxjava2+Rxandroid+okhttp3+Lifecycle 的MVP网络框架,精简Google官方AAC(Android Architecture Components)框架,实现APP生命周期的管理

Global site tag (gtag.js) - Google Analytics