美文网首页
JSON数据解析一键适配PHP

JSON数据解析一键适配PHP

作者: 百吉猫 | 来源:发表于2018-08-27 16:09 被阅读0次

    和服务端小伙伴联调接口时总会遇到json格式的问题,导致客户端无法正常解析数据,出现数据解析异常。本文从客户端角度出发规避解析数据异常,避免重复字段和空指针异常,减少服务端小伙伴的工作量,增加客户端的稳定性

    一,有数据时和无数据时返回数据类型不一致,一般发生在json对象和json数组
        {
            "name": "张三",
            "age": 22,
            "avatar": null,
            "isRegister": false,
            "strings": ["12312", "哈哈", "3213"]          有数据时
        }
        {
            "name": "张三",
            "age": 22,
            "avatar": null,
            "isRegister": false,
            "strings": {}          无数据时
        }
    

    此时客户端解析json时strings字段就会数据类型异常,有数据时是json数组,无数据时是json对象。还有一种类似情况如下

        {
            "name": "张三",
            "age": 22,
            "avatar": {           有数据时
                   "large": "https://pic4.zhimg.com/v2-e552164d8e4ad9beca6eb50140df75b5_b.jpg",
                   "small": "https://pic4.zhimg.com/v2-e552164d8e4ad9beca6eb50140df75b5_b.jpg"
            },
            "isRegister": false,
            "strings": ["12312", "哈哈", "3213"]
        }
        {
            "name": "张三",
            "age": 22,
            "avatar": [],          无数据时
            "isRegister": false,
            "strings": ["12312", "哈哈", "3213"]
        }
    
    二,返回非数值类型时解析数据异常。
        {
            "name": "张三",
            "age": "22",        字符串类型
            "avatar": null,
            "isRegister": false,
            "strings": ["12312", "哈哈", "3213"]
        }
        {
            "name": "张三",
            "age": 22,        整型类型
            "avatar": null,
            "isRegister": false,
            "strings": ["12312", "哈哈", "3213"]
        }
        {
            "name": "张三",
            "age": 22.5,         浮点类型
            "avatar": null,
            "isRegister": false,
            "strings": ["12312", "哈哈", "3213"]
        }
    

    对于age字段就应该是一个整数类型,第一种返回一个字符串“22”,第三种返回浮点数22.5,客户端都会类型强转异常。

    三,布尔类型数据解析异常
        {
            "name": "张三",
            "age": 22,
            "avatar": null,
            "isRegister": false,         布尔类型
            "strings": ["12312", "哈哈", "3213"]
        }
        {
            "name": "张三",
            "age": 22,
            "avatar": null,
            "isRegister": "false",         字符串类型
            "strings": ["12312", "哈哈", "3213"]
        }
        {
            "name": "张三",
            "age": 22,
            "avatar": null,
            "isRegister": 0,         数值类型
            "strings": ["12312", "哈哈", "3213"]
        }
    

    对于isRegister字段就应该是一个布尔类型,第二种返回一个字符串“false”,第三种返回整数类型0,客户端都会类型强转异常。

    四,同一字段在不同接口返回的key不同
        {
            "id": 212,         用户ID
            "age": 22,
            "avatar": null,
            "isRegister": false,
            "strings": ["12312", "哈哈", "3213"]
        }
        {
            "uid": 212,         这也是用户ID
            "age": 22,
            "avatar": null,
            "isRegister": "false",
            "strings": ["12312", "哈哈", "3213"]
        }
        {
            "user_id": 212,        这还是用户ID
            "age": 22,
            "avatar": null,
            "isRegister": 0,
            "strings": ["12312", "哈哈", "3213"]
        }
    

    对于用户ID这个字段时而返回id、时而uid、时而user_id,增加客户端解析难度和误解,如果不慎取错就只能是默认值0或者“”或者null,业务执行逻辑就会错误或者崩溃

    五,json数组中返回null的对象,这是最可怕的一种,线上已经验证过。
        {
            "name": "张三",
            "age": 22,
            "avatar": null,
            "isRegister": false,
            "strings": null         会验证空指针,客户端不会崩溃
        }
        {
            "name": "张三",
            "age": 22,
            "avatar": null,
            "isRegister": "false",
            "strings": []         会验证数组长度,客户端不会崩溃
        }
        {
            "name": "张三",
            "age": 22,
            "avatar": null,
            "isRegister": 0,
            "strings": ["哈哈", null, "3213"]         不会验证数组中的顶级对象是否为null,客户端会崩溃
        }
    

    对于json数组返回null或者[],客户端都会验证不会发生崩溃,如果返回["哈哈", null, "3213"],因为客户端不会验证数组中的顶级对象是否为null,所以会崩溃

    针对上述五种异常,客户端分别对应五种解决方式。服务端小伙伴再也不用不厌其烦的改动,客户端一处配置处处生效,无需重复代码,避免解析异常,减少崩溃。

    一,有数据时和无数据时返回数据类型不一致 and json数组中返回null的对象

    (1)针对json对象 registerTypeAdapterFactory(new ObjectTypeAdapterFactory())GsonBuilder,注册ObjectTypeAdapterFactory对象,代理解析json对象

        try {
            JsonElement tree = elementAdapter.read(in);
            if (delegate instanceof Adapter) {
                if (!tree.isJsonObject()) {        判断是否是json对象
                    return null;         否?返回默认null,执行下一字段解析
                } else {
                    return delegate.fromJsonTree(tree);        是?正常解析数据
                }
            } else {
                return delegate.fromJsonTree(tree);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;         抓住发生的异常,返回默认值null,执行下一字段解析
        }
    

    (2)针对json数组registerTypeAdapter(List.class, new ListDeserializer())GsonBuilder,注册ListDeserializer对象,代理解析json数组

            if (json.isJsonArray()) {         判断是否是json数组
                Gson newGson = new Gson();
                List<?> list = newGson.fromJson(json, typeOfT);         是?正常解析数据
                if (list == null) return Collections.EMPTY_LIST;         解析数组为null ? 返回默认空数组,执行下一字段解析
                list.removeAll(Collections.singleton(null));         数组为其中顶级元素为null ? 移除null元素,改变数组长度
                return list;
            } else {
                return Collections.EMPTY_LIST;        否?返回默认空数组,执行下一字段解析
            }
    
    二,返回非数值类型时解析数据异常

    registerTypeAdapter(Integer.class, new IntegerDeserializer())
    registerTypeAdapter(Long.class, new LongDeserializer())
    registerTypeAdapter(Float.class, new FloatDeserializer())
    registerTypeAdapter(Double.class, new DoubleDeserializer())GsonBuilder,注册对应的数值类型Deserializer对象,代理解析数值类,分别解析整型,长整型,单精度浮点型,双精度浮点型

            try {
                return (int) json.getAsJsonPrimitive().getAsDouble();        默认用双精度浮点型解析在转换为想要的类型
            } catch (Exception e) {
                e.printStackTrace();
                return 0;    出现异常返回默认值0,执行下一字段解析
            }
    
    三,布尔类型数据解析异常

    registerTypeAdapter(Boolean.class, new BooleanSerializer())GsonBuilder,注册BooleanSerializer对象,代理解析布尔类型

            try {
                if (json.getAsJsonPrimitive().isNumber()) {        是否返回的是数值类型
                    return json.getAsJsonPrimitive().getAsDouble() != 0F;         是 ? 数值 == 0 时 为 false  非 0 为 true
                } else {
                    return json.getAsJsonPrimitive().getAsBoolean();          否直接解析布尔值
                }
            } catch (Exception e) {
                e.printStackTrace();
                return false;    出现异常返回默认值false,执行下一字段解析
            }
    
    四,同一字段在不同接口返回的key不同

    此种情况需要为单独的解析实体类配置。例如搜索接口返回的结果,@SerializedName可配置多种字段,客户端只用一个字段接收,任你服务端千变万化,我自客户端岿然不动。

        @SerializedName(value = "title", alternate = {"session_name"})
        public String title;
        @SerializedName(value = "logo_cover", alternate = {"image_phone"})
        public String logo_cover;
        public String logo_detail;
        public int calorie;
        @SerializedName(value = "sessionCount", alternate = {"session_count"})
        public int sessionCount;
        @SerializedName(value = "peopleCount", alternate = {"downloads"})
        public int peopleCount;
        public String category_name;
        public int content_type;
        @SerializedName(value = "id", alternate = {"programId", "sessionId"})
        public int id;
    

    总结

    Q1,一个字段时而有时而没有,客户端会出现异常吗?
    不会异常不会崩溃,只要不影响业务逻辑,服务端怎么简单怎么来。
    Q2,一个字段返回的类型和客户端定义的类型不一致,能正常解析道数据吗?默认值分别是什么?

    • 数值类型/字符串类型对应json各种格式

        {
            "age":22,      数值类型
            "age":"22",      字符串类型
            "age":{},      布尔类型
            "age":{},      对象类型
            "age":[],      数组类型
        }
      

    json数值类型和json字符串类型都能正确解析数据,其他类型会忽略解析异常,数值类型默认值0,字符串类型默认值为“”。

    • 布尔类型对应json各种格式

        {
            "isRegister":0,      数值类型
            "isRegister":false      布尔类型
            "isRegister":"false",      字符串类型布尔值
            "isRegister":"哈哈",      字符串类型非布尔值
            "isRegister":{},      对象类型
            "isRegister":[],      数组类型
        }
      

    json数值类型时,0为false非0为true。json布尔类型和json字符串类型布尔值都能正确解析数据。其他类型会忽略解析异常,数值类型默认值false。

    • 对象和数组

        {
            "avatar":{},      对象类型
            "avatar":[],      数组类型
        }
      

    对象类型和数组类型只有一一对应才能解析道正确数组,其他类型会忽略解析异常,对象默认值为null,数组默认值未空数组。

    服务端小伙伴以后再也不用问我,字段不返回有没有什么问题,我再也不用叮嘱服务端大括号改中括号,中括号改大括号的问题了,完结撒花。
    最后"null" 和 null区别,加了""就是字符串和里面包什么内容没有什么关系,null表明返回的是一个null对象,和客户端对象变量的默认值是一样的。
    源码:https://github.com/YougaKing/GosnFormat.git

    相关文章

      网友评论

          本文标题:JSON数据解析一键适配PHP

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