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

新手上路,请多包涵

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

对于映射,我目前以这种方式使用 Jackson 库中的 ObjectMapper

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

据我了解,上面的代码可以得到显着优化,因为目前 JSONObject 中的数据已经被解析,再次使用 JSONObject.toString() 方法送入序列化-反序列化链然后到 ObjectMapper

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

原文由 Daniel S. 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 700
2 个回答

由于您有一些 JSON 数据的抽象表示( org.json.JSONObject 对象)并且您打算使用 Jackson 库 - 它有自己的 JSON 数据抽象表示( com.fasterxml.jackson.databind.JsonNode ) - 然后从一种表示形式到另一种表示形式的转换将使您免于解析-序列化-解析过程。因此,不是使用接受 StringreadValue 方法,而是使用接受 JsonParser : 89-

 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;
}

请注意,虽然 Jackson 的 JsonNode 可以表示一些额外的类型(例如 BigIntegerDecimal 不是上面代码所必需的所有内容,等等) JSONObject 可以表示。

原文由 mgibsonbr 发布,翻译遵循 CC BY-SA 4.0 许可协议

添加一个旧问题的答案,但是……

Jackson 可以绑定到/从 org.json 类型。通常,它可以通过 _有效地_(尽管不是实际上)序列化为 JSON 和反序列化,在它可以绑定到的任何类型之间进行转换。

如果您注册了 JsonOrgModule ,则可以直接从 ObjectMapper 直接进行转换:

 @Test
public void convert_from_jsonobject() throws Exception {
    JSONObject obj = new JSONObject().put("value", 3.14);
    ObjectMapper mapper = new ObjectMapper().registerModule(new JsonOrgModule());
    PojoData data = mapper.convertValue(obj, PojoData.class);
    assertThat(data.value, equalTo(3.14));
}

@Test
public void convert_to_jsonobject() throws Exception {
    PojoData data = new PojoData();
    data.value = 3.14;
    ObjectMapper mapper = new ObjectMapper().registerModule(new JsonOrgModule());
    JSONObject obj = mapper.convertValue(data, JSONObject.class);
    assertThat(obj.getDouble("value"), equalTo(3.14));
}

public static final class PojoData {
    public double value;
}

我提到这是 有效 的序列化?没错,它将输入对象序列化为 TokenBuffer,它表示 JSON 解析事件流,但构建字符串等的影响较小,因为它可以在很大程度上引用来自输入的数据。然后它将此流提供给反序列化器以生成输出对象。

因此,它有点类似于将 JSONObject 转换为 JsonNode 的建议,但更为通用。它实际上是否更有效需要衡量:要么构造一个 JsonNode 作为中间体,要么构造一个 TokenBuffer,这两种方式都不是没有开销的。

原文由 araqnid 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题