背景
软件开发从数据的角度会经历三个阶段:获取数据,处理数据,展示数据。
获取数据有如下方式:
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());
}
几点说明:
- 选用LinkedHashMap(),可以确保按位置顺序反序列化
- 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());
}
说明:
- 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);
}
说明:
- 单例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,传送门(点击阅读原文,查看代码)
![](https://img.haomeiwen.com/i1933990/28eb61a91f733c41.jpg)
网友评论