Java 使用包含ArrayList的HashMap初始化的JSONObject在某些Android 4版本上初始化不正确-如何修复它? 上下文

Java 使用包含ArrayList的HashMap初始化的JSONObject在某些Android 4版本上初始化不正确-如何修复它? 上下文,java,android,json,couchbase-lite,Java,Android,Json,Couchbase Lite,使用Couchbase Lite()加载json文档的Android应用程序。例如,包含问题列表的问卷: { "questions": [ { "answer": 1, "attributeName": "baiOne", "text": "Some text", "timeOfAnswer": { "timezoneOffset": -60,

使用Couchbase Lite()加载json文档的Android应用程序。例如,包含问题列表的问卷:

{
    "questions": [
        {
            "answer": 1,
            "attributeName": "baiOne",
            "text": "Some text",
            "timeOfAnswer": {
                "timezoneOffset": -60,
                "utcTime": 1458118338993
            }
        },
        ...
    ],
    "endDate": 1458604800000,
    "startDate": 1458086400000,
    "title": "BAI"
}
这是正确加载的

Document doc = database.getDocument(docId);
Map<String, Object> props =
            new HashMap<String, Object>(doc.getProperties());
问题 好的,让我们跳到麻烦制造者:

JSONObject结果=新JSONObject(道具)

在Android 4.4.2(api级别19)及更高版本上,它看起来是正确的:

  • 结果JSONObject中的questions属性(ArrayList)作为JSONArray生成
  • result.toString()被记录:
    {“问题”:[{“答案”:1,“属性名称”:“baiOne”}]}
但对于Android 4.3(api级别18)和4.1.2(api级别16),它看起来并不正确:

  • 结果JSONObject中的questions属性(ArrayList)作为JSONObject生成
    • result.toString()被记录:
      {“问题”:“[{attributeName=baiOne,answer=1}]”
      其中整个问题块被转换成一个大字符串
不相信?完美让我们来看一个简单的回归测试,我在Android仪器测试中使用了这个测试:

@Test
public void testRegression_hashmap_to_json_object()
        throws JSONException, CouchbaseLiteException, IOException {

    Log.v(TAG, "Create data that mimic a json document loaded from coucbase lite:");
    Map<String, Object> question = new HashMap<String, Object>();
    question.put("answer", 1);
    question.put("attributeName", "baiOne");
    List<Map<String, Object>> questions = new ArrayList<Map<String, Object>>();
    questions.add(question);

    Map<String, Object> properties = new HashMap<String, Object>();
    properties.put("questions", questions);

    Log.v(TAG, "Create JSONObject from properties hashmap:");
    JSONObject t = new JSONObject(properties);

    // Do stuff with t ...

    Log.v(TAG, "t.toString(): " + t.toString());
    // prints on android 4.1.2 (16) - 4.3 (18) prints incorrectly:
    // t.toString(): {"questions":"[{attributeName=baiOne, answer=1}]"}
    // android 4.4.2 (19) and up prints correctly:
    // t.toString(): {"questions":[{"answer":1,"attributeName":"baiOne"}]}

    JSONArray a = t.getJSONArray("questions");
    assertTrue(a != null);
    assertTrue(a.length() == 1);

    // Save doc back to couchbase lite
}

根据@Borrden和couchbase lite api/教程(例如)的反馈,解决方案是纯粹使用
new HashMap()
,而根本不使用
JSONObject

根据@Borrden和couchbase lite api/教程(例如)的反馈,解决方案是纯粹使用
new HashMap()
并且根本不要使用
JSONObject

链接的问题似乎有解决方案。你试过了吗?@borrrden thx获得反馈!我应该在这篇文章中提到,另一篇文章中提到的解决方案并不能解决这个问题:在HashMap中作为值的ArrayList没有转换成JSONArray,这最终会导致toString不正确。此外,我不太喜欢引入af custom
jsonifier
…Couchbase Lite使用Java的Jackson序列化库。你可以试试。不过,我不确定这个问题是否与Couchbase Lite直接相关。@Borrden完美的建议!我也在沿着那条路往下看,但是当导入org.codehaus.jackson.map.ObjectMapper已经很晚了,因为它需要aJsonObject.toString()例如:
Map props=new ObjectMapper().readValue(aJsonObject.toString(),HashMap.class)除非我完全错过了api…重点是避免同时使用JSONObject,而是使用Jackson(实际上我不完全清楚这里的目标)。相关问题似乎有一个解决方案。你试过了吗?@borrrden thx获得反馈!我应该在这篇文章中提到,另一篇文章中提到的解决方案并不能解决这个问题:在HashMap中作为值的ArrayList没有转换成JSONArray,这最终会导致toString不正确。此外,我不太喜欢引入af custom
jsonifier
…Couchbase Lite使用Java的Jackson序列化库。你可以试试。不过,我不确定这个问题是否与Couchbase Lite直接相关。@Borrden完美的建议!我也在沿着那条路往下看,但是当导入org.codehaus.jackson.map.ObjectMapper
已经很晚了,因为它需要aJsonObject.toString()例如:
Map props=new ObjectMapper().readValue(aJsonObject.toString(),HashMap.class)除非我完全错过了api…重点是避免同时使用JSONObject,而是使用Jackson(实际上我并不完全清楚这里的目标)。
@Test
public void testRegression_hashmap_to_json_object()
        throws JSONException, CouchbaseLiteException, IOException {

    Log.v(TAG, "Create data that mimic a json document loaded from coucbase lite:");
    Map<String, Object> question = new HashMap<String, Object>();
    question.put("answer", 1);
    question.put("attributeName", "baiOne");
    List<Map<String, Object>> questions = new ArrayList<Map<String, Object>>();
    questions.add(question);

    Map<String, Object> properties = new HashMap<String, Object>();
    properties.put("questions", questions);

    Log.v(TAG, "Create JSONObject from properties hashmap:");
    JSONObject t = new JSONObject(properties);

    // Do stuff with t ...

    Log.v(TAG, "t.toString(): " + t.toString());
    // prints on android 4.1.2 (16) - 4.3 (18) prints incorrectly:
    // t.toString(): {"questions":"[{attributeName=baiOne, answer=1}]"}
    // android 4.4.2 (19) and up prints correctly:
    // t.toString(): {"questions":[{"answer":1,"attributeName":"baiOne"}]}

    JSONArray a = t.getJSONArray("questions");
    assertTrue(a != null);
    assertTrue(a.length() == 1);

    // Save doc back to couchbase lite
}
private JSONObject stringify(Map<String,Object> map) {
    Map<String,Object> fixed = new HashMap<String,Object>();
    for (String key : map.keySet()){
        Object value = map.get(key);
        if (value instanceof Map) {
            value = stringify((Map<String,Object>) value);
        }
        if (value instanceof List) {
            value = stringify(value);
        }
        fixed.put(key,value);
    }
    return new JSONObject(fixed);
}

private JSONArray stringify(Object value) {
    JSONArray a = new JSONArray();
    if (!((List) value).isEmpty() && ((List) value).get(0) instanceof Map) {
        for (Map<String, Object> m: (List<Map<String, Object>>) value) {
            a.put(stringify(m));
        }
    }
    else {
        for (Object m: (List<Object>) value) {
            a.put(m);
        }
    }
    return a;
}