美文网首页
处理gson解析时类型不匹配或者空值问题

处理gson解析时类型不匹配或者空值问题

作者: _非_阳_ | 来源:发表于2019-04-28 18:29 被阅读0次

    android开发的数据几乎都是通过请求拿到后台的json数据,然后将数据解析成对应的Bean

    通常我们会将请求结果封装成一个BaseResponse,比如这样

    package com.mjt.factory.base;
    
    import com.google.gson.annotations.SerializedName;
    
    import java.io.Serializable;
    
    /**
     * Author: zhangsiqi
     * Email: zsq901021@sina.com
     * Date: 2018/1/25
     * Time: 11:09
     * Desc:
     */
    public class BaseResponse<T> implements Serializable {
    
        public BaseResponse(int ret, String message, Error error) {
            this.ret = ret;
            this.message = message;
            this.error = error;
        }
    
        public BaseResponse(int ret, String message, T data) {
            this.ret = ret;
            this.message = message;
            this.data = data;
        }
    
        @SerializedName("ret")
        private int ret;
    
        @SerializedName("msg")
        private String message;
    
        @SerializedName("data")
        private T data;
    
        @SerializedName("error")
        private Error error;
    
        public Error getError() {
            return error;
        }
    
        public int getRet() {
            return ret;
        }
    
        public String getMessage() {
            return message;
        }
    
        public T getData() {
            return data;
        }
    
        public static class Error {
    
            public Error(int code, String msg) {
                this.code = code;
                this.msg = msg;
            }
    
            @SerializedName("code")
            private int code;
            @SerializedName("msg")
            private String msg = "";
    
            public int getCode() {
                return code;
            }
    
            public String getMsg() {
                return msg;
            }
        }
    }
    

    可以看到BaseResponse里data是object类型

    但是遇到开发不规范的后台,如果object为空他会返回给你""或者"null"这样一个空字符串,这时候我们用object类型类接收就会抛一个java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING 的异常

    那么怎么动态的处理这种问题呢

    gson有一个TypeAdapter是可以让开发者自定义处理类型问题的

    package com.mjt.common.utils.gson;
    
    import com.google.gson.Gson;
    import com.google.gson.TypeAdapter;
    import com.google.gson.TypeAdapterFactory;
    import com.google.gson.reflect.TypeToken;
    import com.google.gson.stream.JsonReader;
    import com.google.gson.stream.JsonToken;
    import com.google.gson.stream.JsonWriter;
    
    import java.io.IOException;
    
    /**
     * Copyright:mjt_pad_android
     * Author: liyang <br>
     * Date:2019/3/4 2:35 PM<br>
     * Desc: <br>
     */
    public class GsonTypeAdapterFactory implements TypeAdapterFactory {
        @Override
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
            final TypeAdapter<T> adapter = gson.getDelegateAdapter(this, type);
            return new TypeAdapter<T>() {
                @Override
                public void write(JsonWriter out, T value) throws IOException {
                    adapter.write(out, value);
                }
    
                @Override
                public T read(JsonReader in) throws IOException {
    
                    try {
                        return adapter.read(in);
                    } catch (Throwable e) {
                        consumeAll(in);
                        return null;
                    }
    
                }
    
                private void consumeAll(JsonReader in) throws IOException {
                    if (in.hasNext()) {
                        JsonToken peek = in.peek();
                        if (peek == JsonToken.STRING) {
                            in.nextString();
                        } else if (peek == JsonToken.BEGIN_ARRAY) {
                            in.beginArray();
                            consumeAll(in);
                            in.endArray();
                        } else if (peek == JsonToken.BEGIN_OBJECT) {
                            in.beginObject();
                            consumeAll(in);
                            in.endObject();
                        } else if (peek == JsonToken.END_ARRAY) {
                            in.endArray();
                        } else if (peek == JsonToken.END_OBJECT) {
                            in.endObject();
                        } else if (peek == JsonToken.NUMBER) {
                            in.nextString();
                        } else if (peek == JsonToken.BOOLEAN) {
                            in.nextBoolean();
                        } else if (peek == JsonToken.NAME) {
                            in.nextName();
                            consumeAll(in);
                        } else if (peek == JsonToken.NULL) {
                            in.nextNull();
                        }
                    }
                }
            };
        }
    }
    

    接下来我们来测试一下这个东西起不起作用呢

    json数据正常的情况下是这样
    main方法

     public static void main(String[] args) {
                 String jsonStr="{\"name\":\"Coder\",\"friends\":{\"name\":\"庄长鹏\",\"relation\":\"好朋友\"},\"relation\":\"自己\",\"family\":[{\"name\":\"李克亮\",\"relation\":\"爸爸\"}]}";
    
    //        Gson gson=new GsonBuilder().registerTypeAdapterFactory(new GsonTypeAdapterFactory()).create();
    //        User json=gson.fromJson(jsonStr,User.class);
            User json=new Gson().fromJson(jsonStr,User.class);
            System.out.println(json);
    
     }
    

    User类

        static class User implements Serializable{
            String name;
    
            User friends;
    
            String relation;
    
            List<User> family;
    
            public String getName() {
                return name;
            }
    
            public void setName(String name) {
                this.name = name;
            }
    
            public User getFriends() {
                return friends;
            }
    
            public void setFriends(User friends) {
                this.friends = friends;
            }
    
            public List<User> getFamily() {
                return family;
            }
    
            public void setFamily(List<User> family) {
                this.family = family;
            }
    
            public String getRelation() {
                return relation;
            }
    
            public void setRelation(String relation) {
                this.relation = relation;
            }
    
            @Override
            public String toString() {
                return "User{" +
                        "name='" + name + '\'' +
                        ", friends=" + friends +
                        ", relation='" + relation + '\'' +
                        ", family=" + family +
                        '}';
            }
        }
    
    此时的执行结果为

    User{name='Coder', friends=User{name='庄长鹏', friends=null, relation='好朋友', family=null}, relation='自己', family=[User{name='李克亮', friends=null, relation='爸爸', family=null}]}


    情况一

    如果此时我们将jsonStr改为这样,可以看到name明明是个字符串,但是被我改为{}这样就是object类型了
      public static void main(String[] args) {
            String jsonStr="{\"name\":{},\"friends\":{\"name\":\"庄长鹏\",\"relation\":\"好朋友\"},\"relation\":\"自己\",\"family\":[{\"name\":\"李克亮\",\"relation\":\"爸爸\"}]}";
    
    //        Gson gson=new GsonBuilder().registerTypeAdapterFactory(new GsonTypeAdapterFactory()).create();
    //        User json=gson.fromJson(jsonStr,User.class);
            User json=new Gson().fromJson(jsonStr,User.class);
            System.out.println(json);
    
        }
    
    这时就进行解析就抛了异常了
    Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected STRING but was BEGIN_OBJECT at line 1 column 85 path $.family
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:226)
        at com.google.gson.Gson.fromJson(Gson.java:927)
        at com.google.gson.Gson.fromJson(Gson.java:892)
        at com.google.gson.Gson.fromJson(Gson.java:841)
        at com.google.gson.Gson.fromJson(Gson.java:813)
    

    情况二

    我们再将jsonStr改为这样
        public static void main(String[] args) {
            String jsonStr="{\"name\":\"Coder\",\"friends\":\"\",\"relation\":\"自己\",\"family\":[{\"name\":\"李克亮\",\"relation\":\"爸爸\"}]}";
    
    //        Gson gson=new GsonBuilder().registerTypeAdapterFactory(new GsonTypeAdapterFactory()).create();
    //        User json=gson.fromJson(jsonStr,User.class);
            User json=new Gson().fromJson(jsonStr,User.class);
            System.out.println(json);
    
        }
    
    此时执行又抛异常了
    Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 28 path $.friends
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:226)
        at com.google.gson.Gson$FutureTypeAdapter.read(Gson.java:1011)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
        at com.google.gson.Gson.fromJson(Gson.java:927)
        at com.google.gson.Gson.fromJson(Gson.java:892)
        at com.google.gson.Gson.fromJson(Gson.java:841)
        at com.google.gson.Gson.fromJson(Gson.java:813)
    
    解析又出错了,因为User类中的friends是一个object类型,而jsonStr中的friends却是一个""空字符串

    接下来我们使用TypeAdapter来对上述两种情况进行处理

     public static void main(String[] args) {
            String jsonStr="{\"name\":\"Coder\",\"friends\":\"\",\"relation\":\"自己\",\"family\":[{\"name\":\"李克亮\",\"relation\":\"爸爸\"}]}";
    
            Gson gson=new GsonBuilder().registerTypeAdapterFactory(new GsonTypeAdapterFactory()).create();
            User json=gson.fromJson(jsonStr,User.class);
    //        User json=new Gson().fromJson(jsonStr,User.class);
            System.out.println(json);
    
        }
    

    执行结果为
    User{name='Coder', friends=null, relation='自己', family=[User{name='李克亮', friends=null, relation='爸爸', family=null}]}
    嗯 friends虽然类型不匹配,但是并不影响其他字段的解析

    我们再对第一种情况进行处理
    public static void main(String[] args) {
            String jsonStr="{\"name\":{},\"friends\":{\"name\":\"庄长鹏\",\"relation\":\"好朋友\"},\"relation\":\"自己\",\"family\":[{\"name\":\"李克亮\",\"relation\":\"爸爸\"}]}";
    
            Gson gson=new GsonBuilder().registerTypeAdapterFactory(new GsonTypeAdapterFactory()).create();
           User json=gson.fromJson(jsonStr,User.class);
     //       User json=new Gson().fromJson(jsonStr,User.class);
            System.out.println(json);
    
        }
    

    执行的结果为
    User{name='null', friends=User{name='庄长鹏', friends=null, relation='好朋友', family=null}, relation='自己', family=[User{name='李克亮', friends=null, relation='爸爸', family=null}]}
    嗯 json字符串中的name字段虽然变成了{}对象,但是并不影响其他字段的解析


    回头我们来看看

    GsonTypeAdapterFactory是怎么处理的呢

    • gson 库会通过JsonReader对json对象的每个字段进项读取,当发现类型不匹配时抛出异常
    • 那么我们就在它抛出异常的时候进行处理,让它继续不中断接着往下读取其他的字段就好了
    /**
     * Copyright:mjt_pad_android
     * Author: liyang <br>
     * Date:2019/3/4 2:35 PM<br>
     * Desc: <br>
     */
    public class GsonTypeAdapterFactory implements TypeAdapterFactory {
        @Override
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
            final TypeAdapter<T> adapter = gson.getDelegateAdapter(this, type);
            return new TypeAdapter<T>() {
                @Override
                public void write(JsonWriter out, T value) throws IOException {
                    adapter.write(out, value);
                }
    
                @Override
                public T read(JsonReader in) throws IOException {
                   //gson 库会通过JsonReader对json对象的每个字段进项读取,当发现类型不匹配时抛出异常
                    try {
                        return adapter.read(in);
                    } catch (Throwable e) {
                        //那么我们就在它抛出异常的时候进行处理,让它继续不中断接着往下读取其他的字段就好了
                        consumeAll(in);
                        return null;
                    }
    
                }
    
                private void consumeAll(JsonReader in) throws IOException {
                    if (in.hasNext()) {
                        JsonToken peek = in.peek();
                        if (peek == JsonToken.STRING) {
                            in.nextString();
                        } else if (peek == JsonToken.BEGIN_ARRAY) {
                            in.beginArray();
                            consumeAll(in);
                            in.endArray();
                        } else if (peek == JsonToken.BEGIN_OBJECT) {
                            in.beginObject();
                            consumeAll(in);
                            in.endObject();
                        } else if (peek == JsonToken.END_ARRAY) {
                            in.endArray();
                        } else if (peek == JsonToken.END_OBJECT) {
                            in.endObject();
                        } else if (peek == JsonToken.NUMBER) {
                            in.nextString();
                        } else if (peek == JsonToken.BOOLEAN) {
                            in.nextBoolean();
                        } else if (peek == JsonToken.NAME) {
                            in.nextName();
                            consumeAll(in);
                        } else if (peek == JsonToken.NULL) {
                            in.nextNull();
                        }
                    }
                }
            };
        }
    }
    

    相关文章

      网友评论

          本文标题:处理gson解析时类型不匹配或者空值问题

          本文链接:https://www.haomeiwen.com/subject/gadjnqtx.html