一尘不染

如何有效地将org.json.JSONObject映射到POJO?

json

这个问题一定是以前问过的,但是我找不到。

我正在使用第3方库来检索JSON格式的数据。图书馆将数据作为数据提供给我org.json.JSONObject。我想将此映射JSONObjectPOJO(普通Java对象)以简化访问/代码。

对于映射,我目前ObjectMapper以这种方式使用Jackson图书馆中的:

JSONObject jsonObject = //...
ObjectMapper mapper = new ObjectMapper();
MyPojoClass myPojo = mapper.readValue(jsonObject.toString(), MyPojoClass.class);

据我所知,上述代码可以得到显着优化,因为当前JSONObject已经解析的中的数据将再次通过方法馈入序列化-
反序列化链,JSONObject.toString()然后再馈入ObjectMapper

我想避免这两次转换(toString()和解析)。有没有一种方法可以使用将JSONObject其数据直接映射到POJO?


阅读 359

收藏
2020-07-27

共1个答案

一尘不染

由于您具有一些JSON数据(org.json.JSONObject对象)的抽象表示,并且您打算使用拥有自己的JSON数据抽象表示形式(Jackson)的Jackson库,因此com.fasterxml.jackson.databind.JsonNode从一种表示形式转换为另一种表示形式将使您从解析序列化解析过程。因此,您可以使用接受a的此版本,而不是使用readValue接受a
的方法:StringJsonParser

JSONObject jsonObject = //...
JsonNode jsonNode = convertJsonFormat(jsonObject);
ObjectMapper mapper = new ObjectMapper();
MyPojoClass myPojo = mapper.readValue(new TreeTraversingParser(jsonNode), MyPojoClass.class);

JSON是一种非常简单的格式,因此convertJsonFormat手动创建它并不难。这是我的尝试:

static JsonNode convertJsonFormat(JSONObject json) {
    ObjectNode ret = JsonNodeFactory.instance.objectNode();

    @SuppressWarnings("unchecked")
    Iterator<String> iterator = json.keys();
    for (; iterator.hasNext();) {
        String key = iterator.next();
        Object value;
        try {
            value = json.get(key);
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        if (json.isNull(key))
            ret.putNull(key);
        else if (value instanceof String)
            ret.put(key, (String) value);
        else if (value instanceof Integer)
            ret.put(key, (Integer) value);
        else if (value instanceof Long)
            ret.put(key, (Long) value);
        else if (value instanceof Double)
            ret.put(key, (Double) value);
        else if (value instanceof Boolean)
            ret.put(key, (Boolean) value);
        else if (value instanceof JSONObject)
            ret.put(key, convertJsonFormat((JSONObject) value));
        else if (value instanceof JSONArray)
            ret.put(key, convertJsonFormat((JSONArray) value));
        else
            throw new RuntimeException("not prepared for converting instance of class " + value.getClass());
    }
    return ret;
}

static JsonNode convertJsonFormat(JSONArray json) {
    ArrayNode ret = JsonNodeFactory.instance.arrayNode();
    for (int i = 0; i < json.length(); i++) {
        Object value;
        try {
            value = json.get(i);
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        if (json.isNull(i))
            ret.addNull();
        else if (value instanceof String)
            ret.add((String) value);
        else if (value instanceof Integer)
            ret.add((Integer) value);
        else if (value instanceof Long)
            ret.add((Long) value);
        else if (value instanceof Double)
            ret.add((Double) value);
        else if (value instanceof Boolean)
            ret.add((Boolean) value);
        else if (value instanceof JSONObject)
            ret.add(convertJsonFormat((JSONObject) value));
        else if (value instanceof JSONArray)
            ret.add(convertJsonFormat((JSONArray) value));
        else
            throw new RuntimeException("not prepared for converting instance of class " + value.getClass());
    }
    return ret;
}

需要注意的是,虽然杰克逊的JsonNode可以代表一些额外的类型(如BigIntegerDecimal等),它们是没有必要的,因为上面涵盖了该代码JSONObject可以代表。

2020-07-27