1. 程式人生 > >JsonObject toString() 輸出鍵值對順序研究

JsonObject toString() 輸出鍵值對順序研究

背景

後臺有一套介面,需要對傳參進行排序,於是寫了一套排序方法,在請求介面之前對所有引數排序,這裡邊用到了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,實現有序輸出