JsonObject toString() 輸出鍵值對順序研究
阿新 • • 發佈:2019-01-22
背景
後臺有一套介面,需要對傳參進行排序,於是寫了一套排序方法,在請求介面之前對所有引數排序,這裡邊用到了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,實現有序輸出