美文网首页Android知识Android开发经验谈自定义views
当Json序列化与反序列遇到Map<Object,Obje

当Json序列化与反序列遇到Map<Object,Obje

作者: sugaryaruan | 来源:发表于2017-07-24 11:29 被阅读1909次

    背景

    软件开发从数据的角度会经历三个阶段:获取数据,处理数据,展示数据。

    获取数据有如下方式:
    1. 从数据库获取,
    2. 从网络请求获取,
    3. 从本地生成业务逻辑的数据。

    App客户端上,数据最初来源于后台接口,http请求获取到json字符串,json反序列化生成实体类;在这个反序列化过程中可以生成基本数据类型,JavaBean,数组,集合。集合里有List和Map,平时我们遇到反序列化情况是Map<String,Object>,如果需要序列化成Map<Object,Object>,要怎么处理呢?

    Json格式的表达,是以Key:Value的形式,Key只能是字符串,Value可以是对象或者数据,Map<Object,Object>中Map的键是对象,这要怎么用json表现?

    常用的Json解析库有Gson,Jackson, Fastjson。阿里的Fastjson号称解析速度最快,Jackson解析速度比Gson快,常用在服务器端。谷歌的Gson解析稳定,常在App端使用,在中小数据量解析上和Jackson性能相近。我们来看看这三个库解析的结果

    Gson与Map<Object,Object>

    数据准备,生成Map集合

    private LinkedHashMap<CategoryEntity, List<CategoryEntity>> createMap() {
        LinkedHashMap<CategoryEntity, List<CategoryEntity>> categoryMap = new LinkedHashMap<>();
    
        List<CategoryEntity> firstCategoryList = new ArrayList<>();
        firstCategoryList.add(new CategoryEntity("201", "全部分类", true));
        categoryMap.put(new CategoryEntity("101", "全部分类", true), firstCategoryList);
    
        List<CategoryEntity> secondCategoryList = new ArrayList<>();
        secondCategoryList.add(new CategoryEntity("211", "遥控赛车", false));
        secondCategoryList.add(new CategoryEntity("212", "乐高积木", false));
        secondCategoryList.add(new CategoryEntity("213", "泰迪小熊", false));
        categoryMap.put(new CategoryEntity("111", "儿童玩具", false), secondCategoryList);
    
        List<CategoryEntity> thirdCategoryList = new ArrayList<>();
        thirdCategoryList.add(new CategoryEntity("221", "电磁炉", false));
        thirdCategoryList.add(new CategoryEntity("222", "电饭煲", false));
        categoryMap.put(new CategoryEntity("121", "厨房用品", false), thirdCategoryList);
    
        List<CategoryEntity> fourthCategoryList = new ArrayList<>();
        fourthCategoryList.add(new CategoryEntity("231", "Java8函数式编程", false));
        fourthCategoryList.add(new CategoryEntity("232", "美的历程", false));
        fourthCategoryList.add(new CategoryEntity("232", "黑客与画家", false));
        fourthCategoryList.add(new CategoryEntity("232", "代码的未来", false));
        categoryMap.put(new CategoryEntity("131", "自营书籍", false), fourthCategoryList);
    
        return categoryMap;
    }
    

    Gson的序列化和反序列示例代码:

    private void gsonTest() {
        LinkedHashMap<CategoryEntity, List<CategoryEntity>> linkedHashMap = createMap();
        String toJson = GsonUtil.getInstance().toJson(linkedHashMap);
        LOG.D(TAG, "toJson = " + toJson);
    
        LinkedHashMap<CategoryEntity, List<CategoryEntity>> parserMap =
                GsonUtil.getInstance().fromJson(
                        toJson,
                        new TypeToken<LinkedHashMap<CategoryEntity, List<CategoryEntity>>>() {
                        }.getType());
        LOG.D(TAG, "fromJson = " + parserMap.toString());
        List<CategoryEntity> parseCategoryList = parserMap.get(new CategoryEntity("121", "厨房用品", false));
        LOG.D(TAG, "parseCategoryList = " + parseCategoryList.toString());
    }
    

    几点说明:

    1. 选用LinkedHashMap(),可以确保按位置顺序反序列化
    2. GsonUtil单例模式,反序列化类型通过TypeToken来指定

    序列化结果如下:

    [
    [
        {
            "id": "101",
            "isSelected": true,
            "name": "全部分类"
        },
        [
            {
                "id": "201",
                "isSelected": true,
                "name": "全部分类"
            }
        ]
    ],
    [
        {
            "id": "111",
            "isSelected": false,
            "name": "儿童玩具"
        },
        [
            {
                "id": "211",
                "isSelected": false,
                "name": "遥控赛车"
            },
            {
                "id": "212",
                "isSelected": false,
                "name": "乐高积木"
            },
            {
                "id": "213",
                "isSelected": false,
                "name": "泰迪小熊"
            }
        ]
    ],
    [
        {
            "id": "121",
            "isSelected": false,
            "name": "厨房用品"
        },
        [
            {
                "id": "221",
                "isSelected": false,
                "name": "电磁炉"
            },
            {
                "id": "222",
                "isSelected": false,
                "name": "电饭煲"
            }
        ]
    ],
    [
        {
            "id": "131",
            "isSelected": false,
            "name": "自营书籍"
        },
        [
            {
                "id": "231",
                "isSelected": false,
                "name": "Java8函数式编程"
            },
            {
                "id": "232",
                "isSelected": false,
                "name": "美的历程"
            },
            {
                "id": "232",
                "isSelected": false,
                "name": "黑客与画家"
            },
            {
                "id": "232",
                "isSelected": false,
                "name": "代码的未来"
            }
        ]
    ]
    ] 
    

    小结:
    Gson序列化LinkedHashMap, 它会把Map的Key部分和Value部分放在同一层级,作为数组的元素。

    Jackson与Map<Object,Object>

    使用jackson序列化/反序列化代码:

    private void jackJsonTest(){
        LinkedHashMap<CategoryEntity, List<CategoryEntity>> linkedHashMap = createMap();
        String json = JacksonUtil.getInstance().toJson(linkedHashMap);
        LOG.D(TAG, "jackJson = " + json);
    
        LinkedHashMap<CategoryEntity, List<CategoryEntity>> parseMap = JacksonUtil.getInstance().fromJson(
                json,
                new com.fasterxml.jackson.core.type.TypeReference<LinkedHashMap<CategoryEntity,List<CategoryEntity>>>() {});
        LOG.D(TAG, "parse map = " + parseMap.toString());
        List<CategoryEntity> categoryEntityList = parseMap.get(new CategoryEntity("121", "厨房用品", false));
        LOG.D(TAG, "jackson list = " + categoryEntityList.toString());
    }
    

    说明:

    1. JacksonUtil使用单例,通过TypeReference指定jackson反序列的类型

    Jackson解析结果如下:

    {
    "CategoryEntity{id='101', name='全部分类', isSelected=true}": [
        {
            "id": "201",
            "name": "全部分类",
            "selected": true
        }
    ],
    "CategoryEntity{id='111', name='儿童玩具', isSelected=false}": [
        {
            "id": "211",
            "name": "遥控赛车",
            "selected": false
        },
        {
            "id": "212",
            "name": "乐高积木",
            "selected": false
        },
        {
            "id": "213",
            "name": "泰迪小熊",
            "selected": false
        }
    ],
    "CategoryEntity{id='121', name='厨房用品', isSelected=false}": [
        {
            "id": "221",
            "name": "电磁炉",
            "selected": false
        },
        {
            "id": "222",
            "name": "电饭煲",
            "selected": false
        }
    ],
    "CategoryEntity{id='131', name='自营书籍', isSelected=false}": [
        {
            "id": "231",
            "name": "Java8函数式编程",
            "selected": false
        },
        {
            "id": "232",
            "name": "美的历程",
            "selected": false
        },
        {
            "id": "232",
            "name": "黑客与画家",
            "selected": false
        },
        {
            "id": "232",
            "name": "代码的未来",
            "selected": false
        }
    ]
    }
    

    小结:Jackson在序列化Map时,会把Map的Key对应的对象默认解析成字符串;但是这个字符串格式不是Json的格式,通过添加自定义Map的键的序列化解析类和反序列化解析类,可以实现对CategoryEntity对象Json序列化/反序列化

    public JacksonParser() {
        mObjectMapper = new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addKeyDeserializer(CategoryEntity.class, new MapKeyDeserializer());
        simpleModule.addKeySerializer(CategoryEntity.class, new MapKeySerializer(CategoryEntity.class));
        mObjectMapper.registerModule(simpleModule);
    }
    

    Fastjson与Map<Object,Object>

    Fastjson序列化和反序列示例

    private void fastJsonTest() {
         LinkedHashMap<CategoryEntity, List<CategoryEntity>> linkedHashMap = createMap();
         String s = FastJsonUtil.getInstance().toJson(linkedHashMap);
         LOG.D(TAG, "fastJson = " + s);
    }
    

    说明:

    1. 单例FastJsonUtil,通过TypeReference来指定反序列化类型

    解析结果

    {
    {"id":"101","name":"全部分类","selected":true}
        :[{"id":"201","name":"全部分类","selected":true}],
    
    {"id":"111","name":"儿童玩具","selected":false}
        :[{"id":"211","name":"遥控赛车","selected":false},{"id":"212","name":"乐高积木","selected":false},{"id":"213","name":"泰迪小熊","selected":false}],
    
    {"id":"121","name":"厨房用品","selected":false}
        :[{"id":"221","name":"电磁炉","selected":false},{"id":"222","name":"电饭煲","selected":false}],
    
    {"id":"131","name":"自营书籍","selected":false}
        :[{"id":"231","name":"Java8函数式编程","selected":false},{"id":"232","name":"美的历程","selected":false},{"id":"232","name":"黑客与画家","selected":false},{"id":"232","name":"代码的未来","selected":false}]
    }
    

    小结:fastjson序列化Map,生成的字符串不是json格式,Key部分直接序列化成对象。通过{}:[]这种格式来表现Map<CategoryEntity,List<CategoryEntity>>的key和value。

    总结

    开发中,较少会遇到需要序列化Map<Object,Object>,即使遇到了也可以通过改变实体类的数据结构来规避这种解析,把Key的Object对象放入到Value的对象里,组成新的实体类,而Map的Key用String来表示。因此,本例的Map<CategoryEntity,List<CategoryEntity>>,可以把Map的Key部分的对象Category放入到List集合的里。这样,在某些场景,把二维层面的数据,降为一维数据,通过链式的调用来获取原来二维的数据,把数据维度转化成了链式调用的深度。

    示例代码上传到Github上了,欢迎Star,传送门(点击阅读原文,查看代码)

    欢迎关注CodeThings公众号

    相关文章

      网友评论

        本文标题:当Json序列化与反序列遇到Map<Object,Obje

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