JsonObject toString() 输出键值对顺序研究

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/immrwk/article/details/79354562

背景

后台有一套接口,需要对传参进行排序,于是写了一套排序方法,在请求接口之前对所有参数排序,这里边用到了JsonObject及其自身的toString方法,测试过程中发现在一台android4.4系统的手机上程序运行不是预期结果,于是有了下面的研究

经过分析发现,问题出现的原因是JsonObject toString输出的键值对顺序不是固定的,并不是一定按照我们put元素进入的顺序输出,所以导致后面传递参数的顺序出了问题,下面看一下为什么object.toString输出顺序不固定

JsonObject部分源码如下:

public JSONObject() {  
    nameValuePairs = new HashMap<String, Object>();  
} 
public JSONObject put(String name, Object value) throws JSONException {  
        if (value == null) {  
            nameValuePairs.remove(name);  
            return this;  
        }  
        if (value instanceof Number) {  
            // deviate from the original by checking all Numbers, not just floats & doubles  
            JSON.checkDouble(((Number) value).doubleValue());  
        }  
        nameValuePairs.put(checkName(name), value);  
        return this;  
    } 

我们发现,JsonObject中存储数据用的是HashMap,而HashMap并不是顺序存储数据的。
这时要想让object.toString输出的顺序,就需要自定义一个JsonObject,使用有序的LinkedHashMap代替无序的HashMap来进行数据存储

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONStringer;

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedJsonObject extends JSONObject {

    private LinkedHashMap<Object, Object> nameValuePairs;

    public LinkedJsonObject() {
        nameValuePairs = new LinkedHashMap<>();
    }

    @Override
    public JSONObject put(String name, int value) throws JSONException {
        return put(name, value);
    }

    @Override
    public JSONObject put(String name, long value) throws JSONException {
        return put(name, value);
    }

    @Override
    public JSONObject put(String name, double value) throws JSONException {
        return put(name, value);
    }

    @Override
    public JSONObject put(String name, boolean value) throws JSONException {
        return put(name, value);
    }

    @Override
    public JSONObject put(String name, Object value) throws JSONException {

        checkName(name);

        if (value == null) {
            nameValuePairs.remove(name);
            return this;
        }
        if (value instanceof Double) {
            if (((Double) value).isInfinite() || ((Double) value).isNaN()) {
                throw new JSONException("JSON does not allow non-finite numbers.");
            }
        } else if (value instanceof Float) {
            if (((Float) value).isInfinite() || ((Float) value).isNaN()) {
                throw new JSONException("JSON does not allow non-finite numbers.");
            }
        }
        nameValuePairs.put(name, value);

        return this;
    }


    String checkName(String name) throws JSONException {
        if (name == null) {
            throw new JSONException("Names must be non-null");
        }
        return name;
    }

    public String toString() {
        try {
            Iterator<Object> keys = nameValuePairs.keySet().iterator();
            StringBuffer sb = new StringBuffer("{");

            while (keys.hasNext()) {
                if (sb.length() > 1) {
                    sb.append(',');
                }
                Object o = keys.next();
                sb.append(quote(o.toString()));
                sb.append(':');
                sb.append(valueToString(nameValuePairs.get(o)));
            }
            sb.append('}');
            return sb.toString();
        } catch (Exception e) {
            return null;
        }
    }

    static String valueToString(Object value) throws JSONException {
        if (value == null || value.equals(null)) {
            return "null";
        }
        if (value instanceof JSONStringer) {
            Object o;
            try {
                o = ((JSONStringer) value).toString();
            } catch (Exception e) {
                throw new JSONException(e.getMessage());
            }
            if (o instanceof String) {
                return (String) o;
            }
            throw new JSONException("Bad value from toJSONString: " + o);
        }
        if (value instanceof Number) {
            return numberToString((Number) value);
        }
        if (value instanceof Boolean || value instanceof JSONObject || value instanceof JSONArray) {
            return value.toString();
        }
        if (value instanceof Map) {
            return new JSONObject((Map) value).toString();
        }
        if (value instanceof Collection) {
            return new JSONArray((Collection) value).toString();
        }
        return quote(value.toString());
    }
}

在最新的Android源码中, JsonObject中数据存储已经由HashMap更换为了LinkedHashMap,实现有序输出

参考:
1.http://blog.csdn.net/ben0612/article/details/44591161

猜你喜欢

转载自blog.csdn.net/immrwk/article/details/79354562