zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Oracle数据库中心双活之道:ASM vs VPLEX
    使用Visual C ++和Open Folder自定义环境
    HDU 2563 统计问题(递归,思维题)
    彻底搞定C语言指针(精华版)
    HDU 1000 A + B Problem(指针版)
    图的基本算法(BFS和DFS)
    HDU 1312 Red and Black(DFS,板子题,详解,零基础教你代码实现DFS)
    C语言求最小公倍数和最大公约数三种算法(经典)
    HDU 2504 又见GCD(最大公约数与最小公倍数变形题)
    HDU 2502 月之数(二进制,规律)
  • 原文地址:https://www.cnblogs.com/nuccch/p/9729781.html
Copyright © 2011-2022 走看看