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

原文地址:https://www.cnblogs.com/nuccch/p/9729781.html

时间: 2024-10-06 16:52:15

fastjson存在乱序的问题的相关文章

fastjson序列化乱序问题

1.初始化为有序json对象 JSONObject jsonOrdered= new JSONObject(true); 2.将String对象转换过程中,不要调整顺序 JSONObject jsonOrdered = JSONObject.parseObject(jsonString, Feature.OrderedField);

数据库存储数据乱序问题

由于提交的留言数据在网页端查询出来的时候,一直存在乱序的问题,有时候新留言插在旧留言的后面,有时候又插在前面,实在是头疼 尝试了一下解决方案 将数据库的存储引擎修改为innoDB 将排序规则修改为utf8_general_ci 这样的话排序就是正常了 由于留言需要倒叙排序,最新的留言显示在最上面,需要在php中将select语句进行处理 使用SELECT * FROM `messages` ORDER BY `messages_id` DESC 就可以了

写一个函数实现数组中的元素随机乱序排序

//原生JS写一个函数实现一个shuffle方法,将数组中的元素随机乱序排序 var shuffle = function(arr){ var len,t,rand; for(var i =0;len = arr.length,i<len;i++){ rand = parseInt(Math.random()*len);//parseInt(Math.random()*(len-1-0)+1);或者rand = Math.floor(Math.random()*(len-1-0)+1);即Mat

2015-4-2的阿里巴巴笔试题:乱序的序列保序输出(bit数组实现hash)

分布式系统中的RPC请求经常出现乱序的情况.写一个算法来将一个乱序的序列保序输出.例如,假设起始序号是1,对于(1, 2, 5, 8, 10, 4, 3, 6, 9, 7)这个序列,输出是:123, 4, 567, 8, 9, 10 上述例子中,3到来的时候会发现4,5已经在了.因此将已经满足顺序的整个序列(3, 4, 5)输出为一行. 1 #include<stdio.h> 2 3 int main() 4 { 5 int num ; 6 while(scanf("%d"

NSArray的排序和乱序

1 NSArray *array = @[@(3),@(4),@(1),@(2),@(5)]; 2 //升序 3 NSArray *array1 = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { 4 return [obj1 compare:obj2]; 5 }]; 6 NSLog(@"%@",array1); 7 8 //降序 9 NSArray *array2 = [array s

AS3.0 扑克牌乱序排列法洗牌

package { /* *@ClassName:package::PokerMain *@Intro:这是一个初始化1-52扑克牌,然后进行乱序排列进行洗牌: *@Author:非若 *@Date:2015.07.22 *@LanguageVersion:ActionScript 3.0 * */ import flash.display.Sprite; public class PokerMain extends Sprite { //设置扑克牌总数 private var NUM:Numb

Fisher-Yates 乱序算法

这两篇博客[1][2]的模式是我心仪的一种科技博客的方式,提供源代码,显示运行图形结果,通俗地介绍理论原理. 直接把结论摘录下来吧. 随机算法如果写成如下形式 randomIndex = random.randint(0, len(items) - 1) 则得到一个偏序的结果,正确的写法是 randomIndex = random.randint(i, len(items) - 1) 只有这样,才能得到无偏的结果. 注: 所谓无偏,简单理解就是给定一个数组,随机乱序 n 多次,那么得到的结果应该

IOCP 乱序

         关于IOCP乱序的探讨                   2011-07-14 10:55:49 标签:职场 休闲 IOCP乱序 关于IOCP的探讨 本文主要探讨一下windows平台上的完成端口开发及其与之相关的几个重要的技术概念,这些概念都是与基于IOCP的开发密切相关的,对开发人员来讲,又不得不给予足够重视的几个概念: 1) 基于IOCP实现的服务吞吐量 2)IOCP模式下的线程切换 3)基于IOCP实现的消息的乱序问题. 一.IOCP简介     提到IOCP,大家都

使用块代码实现数组排序和乱序

1 #import "HMViewController.h" 2 3 @interface HMViewController () 4 5 @end 6 7 @implementation HMViewController 8 9 - (void)viewDidLoad 10 { 11 [super viewDidLoad]; 12 13 // 块代码 14 NSArray *array = @[@(1), @(2), @(3), @(4), @(5)]; 15 16 // 排序 17