fastjson存在乱序的问题
现象及原因
通常来讲,在使用json数据格式时一般不需要要求数据有序。但凡事都有例外,针对查询时序数据这样一个场景,就必须要求服务器端返回的数据是按时间有序的,否则前端在进行数据展示时就会有问题。
项目架构如下:

数据从OpenTSDB中查询出来的时候是有序的:
[{
"metrc":"cpu.usage",
"dps": {
"123456": 12,
"123457": 13,
"123458": 23,
"123459": 32
}
}]
执行如下操作:
JSONObject.parseArray(json)
结果查看对应的JSON数组中的map数据是乱序的,可能的结果如下:
[{
"metrc":"cpu.usage",
"dps": {
"123457": 13,
"123456": 12,
"123459": 32,
"123458": 23
}
}]
原本希望时序数据是按时间Key有序的,但是经过fastjson解析之后就会出现Key乱序。实际上,这个问题是fastjson本身的bug,详见:https://github.com/alibaba/fastjson/issues/660 。
解决办法
如下以解析从OpenTSDB中查询返回的时序数据为例。
1.升级fastjson版本
fastjson从1.2.3版本开始,在解析json对象时可以指定Feature.OrderedField参数,这样解析的结果就不会乱序。
public static void main(String[] args) {
// 模拟从OpenTSDB中查询返回的时序数据
String str = "[{\"metric\":\"temperature\",\"tags\":{\"device_id\":\"device-12312-14\",\"dt_name\":\"dsdsdsd\"},\"aggregateTags\":[],\"dps\":{\"1538210186542\":30,\"1538210191574\":83,\"1538210196597\":41,\"1538210201624\":56,\"1538210206654\":20,\"1538210211677\":25,\"1538210216700\":54,\"1538210221740\":36,\"1538210226773\":89,\"1538210231813\":8,\"1538210236847\":34,\"1538210241882\":83,\"1538210246916\":96,\"1538210251952\":42,\"1538210257002\":6,\"1538210262038\":87,\"1538210267076\":19,\"1538210272108\":44,\"1538210277139\":84,\"1538210282176\":41,\"1538210287216\":57,\"1538210292254\":26,\"1538210297283\":64}}]";
// 直接使用fastjson的接口实现有序解析
JSONArray array = JSONArray.parseObject(str.getBytes(), JSONArray.class, Feature.OrderedField);
System.out.println(array.getJSONObject(0).getJSONObject("dps").toJSONString());
}
实际上,追踪一下fastjson的实现源码发现,当传递参数Feature.OrderedField时,底层正是使用LinkedHashMap来实现Key有序的(LinkedHashMap是按插入顺序排序):
public JSONObject(int initialCapacity, boolean ordered){
if (ordered) {
// 使用LinkedHashMap保证json对象的key是按照插入顺序有序的
map = new LinkedHashMap<String, Object>(initialCapacity);
} else {
map = new HashMap<String, Object>(initialCapacity);
}
}
2.手动排序
除了可以直接通过fastjson的接口在解析时就实现有序,还可以对解析结果进行手动排序。
public static void main(String[] args) {
// 模拟从OpenTSDB中查询返回的时序数据
String str = "[{\"metric\":\"temperature\",\"tags\":{\"device_id\":\"device-12312-14\",\"dt_name\":\"dsdsdsd\"},\"aggregateTags\":[],\"dps\":{\"1538210186542\":30,\"1538210191574\":83,\"1538210196597\":41,\"1538210201624\":56,\"1538210206654\":20,\"1538210211677\":25,\"1538210216700\":54,\"1538210221740\":36,\"1538210226773\":89,\"1538210231813\":8,\"1538210236847\":34,\"1538210241882\":83,\"1538210246916\":96,\"1538210251952\":42,\"1538210257002\":6,\"1538210262038\":87,\"1538210267076\":19,\"1538210272108\":44,\"1538210277139\":84,\"1538210282176\":41,\"1538210287216\":57,\"1538210292254\":26,\"1538210297283\":64}}]";
// 解析之后手动排序
JSONArray array = JSONArray.parseArray(str);
System.out.println(array.toJSONString());
JSONObject json = array.getJSONObject(0);
// 不传递参数Feature.OrderedField时解析得到的json对象key是无序的,本质上是一个HashMap结构
Map<String, Object> map = json.getJSONObject("dps").getInnerMap();
// 通过TreeMap对Key进行排序
map = sortMapByKey(map);
JSONObject dps = new JSONObject();
dps.put("dps", map);
System.out.println(dps.toJSONString());
}
private static Map<String, Object> sortMapByKey(Map<String, Object> map) {
if (map == null || map.isEmpty()) {
return null;
}
Map<String, Object> sortMap = new TreeMap<String, Object>(new MapKeyComparator());
sortMap.putAll(map);
return sortMap;
}
private static class MapKeyComparator implements Comparator<String> {
@Override
public int compare(String str1, String str2) {
return str1.compareTo(str2);
}
}
【参考】
https://dzone.com/articles/hashmap-vs-treemap-vs HashMap vs. TreeMap vs. HashTable vs. LinkedHashMap
fastjson存在乱序的问题的更多相关文章
- fastjson序列化乱序问题
1.初始化为有序json对象 JSONObject jsonOrdered= new JSONObject(true); 2.将String对象转换过程中,不要调整顺序 JSONObject json ...
- FastJson乱序问题
1.初始化为有序json对象 JSONObject jsonOrdered= new JSONObject(true); 2.将String对象转换过程中,不要调整顺序 JSONObject json ...
- fast json 乱序问题解决过程
解决问题:保存到redis中的jsonstring在转回jsonObject的时候乱序: 解决方案:https://inlhx.iteye.com/blog/2312512 解决过程: 1 看fast ...
- 由乱序播放说开了去-数组的打乱算法Fisher–Yates Shuffle
之前用HTML5的Audio API写了个音乐频谱效果,再之后又加了个播放列表就成了个简单的播放器,其中弄了个功能是'Shuffle'也就是一般播放器都有的列表打乱功能,或者理解为随机播放. 但我觉得 ...
- iOS之数组的排序(升序、降序及乱序)
#pragma mark -- 数组排序方法(升序) - (void)arraySortASC{ //数组排序 //定义一个数字数组 NSArray *array = @[@(3),@(4),@(2) ...
- volatile关键字及编译器指令乱序总结
本文简单介绍volatile关键字的使用,进而引出编译期间内存乱序的问题,并介绍了有效防止编译器内存乱序所带来的问题的解决方法,文中简单提了下CPU指令乱序的现象,但并没有深入讨论. 以下是我搭建的博 ...
- Fisher-Yates 乱序算法
这两篇博客[1][2]的模式是我心仪的一种科技博客的方式,提供源代码,显示运行图形结果,通俗地介绍理论原理. 直接把结论摘录下来吧. 随机算法如果写成如下形式 randomIndex = random ...
- TCP协议下大数据传输IOCP乱序问题
毕业后稀里糊涂的闭门造车了两年,自己的独立博客也写了两年,各种乱七八糟,最近准备把自己博客废了,现在来看了下这两年写的对我来说略微有点意义的文章只此一篇,转载过来以作留念. 写的很肤浅且凌乱,请见谅. ...
- 疯狂位图之——位图生成12GB无重复随机乱序大整数集
上一篇讲述了用位图实现无重复数据的排序,排序算法一下就写好了,想弄个大点数据测试一下,因为小数据在内存中快排已经很快. 一.生成的数据集要求 1.数据为0--2147483647(2^31-1)范围内 ...
随机推荐
- 1 minute教会你shell
Shell模板 #!/bin/bash ####################################################### # $Name: shell_template. ...
- app.config的坑
C# C/S程序一般通过ConfigurationManager类来读取app.config,其中有个坑爹的地方是ConfigurationManager类自带缓存,就如Windows服务来说,除非重 ...
- 基于CAS在.NET中实现SSO单点登录
单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一.SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统. 单点登录原理 ...
- Hexo server报错TypeError: Cannot read property 'utcOffset' of null解决方法
最近刚刚开始使用Hexo,新建了一篇article,运行hexo server时候总是报错Cannot read property 'offset' of null. 最后发现是因为手贱把_confi ...
- C#:往数据库插入/更新时候关于NUll空值的处理
前几天遇到一个问题,找了好久才找到解决办法.不过也很开心,终于解决了. 问题:前端当我数据为空的时候不赋值,传到后台也为空的时候(注意:是Null不是""),SqlCommand对 ...
- Java 8 Stream介绍及使用2
(原) stream中另一些比较常用的方法. 1. public static<T> Stream<T> generate(Supplier<T> s) 通过gen ...
- Java SpringBoot集成RabbitMq实战和总结
目录 交换器.队列.绑定的声明 关于消息序列化 同一个队列多消费类型 注解将消息和消息头注入消费者方法 关于消费者确认 关于发送者确认模式 消费消息.死信队列和RetryTemplate RPC模式的 ...
- libgdx学习记录2——文字显示BitmapFont
libgdx对中文支持不是太好,主要通过Hireo和ttf字库两种方式实现.本文简单介绍最基本的bitmapfont的用法. 代码如下: package com.fxb.newtest; import ...
- git@github.com: Permission denied (publickey).////remote: Permission to xxx/test.git denied to xxx.等权限问题
Error msg git@github.com: Permission denied (publickey) 或者: remote: Permission to xxx/test.git denie ...
- tps 和 qps的区别
QPS:Queries Per Second意思是“每秒查询率”,是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准. TPS:是Transactions ...