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

Dan*_* S. 28 java mapping json jackson mapper

以前一定要问过这个问题,但我找不到.

我正在使用第三方库来检索JSON格式的数据.图书馆向我提供数据org.json.JSONObject.我想将其映射JSONObjectPOJO(Plain Old Java Object)以获得更简单的访问/代码.

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

JSONObject jsonObject = //...
ObjectMapper mapper = new ObjectMapper();
MyPojoClass myPojo = mapper.readValue(jsonObject.toString(), MyPojoClass.class);
Run Code Online (Sandbox Code Playgroud)

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

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

mgi*_*nbr 28

由于您有一些JSON数据(一个org.json.JSONObject对象)的抽象表示,并且您计划使用Jackson库 - 它有自己的JSON数据(com.fasterxml.jackson.databind.JsonNode)的抽象表示- 然后从一个表示到另一个表示的转换将使您免于parse-serialize-parse进程.因此,而不是使用readValue接受的方法String,你会使用这个版本,它接受一个JsonParser:

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

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;
}
Run Code Online (Sandbox Code Playgroud)

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


Ste*_*gne 23

如果你没有与杰克逊联系,你可以使用方便的谷歌 - 戈森图书馆作为替代.它只需要一个罐子,使用起来非常简单:

将java对象转换为JSON字符串:

  String json_string = new Gson().toJson(an_object);
Run Code Online (Sandbox Code Playgroud)

从JSON字符串创建java对象:

  MyObject obj = new Gson().fromJson(a_json_string, MyObject.class);
Run Code Online (Sandbox Code Playgroud)

我不知道与杰克逊相比的性能,但它很难比这简单...... Gson是一个稳定且广泛使用的库.

请访问https://code.google.com/p/google-gson/

  • 抱歉,这不是我问题的答案。您的代码也没有绕过双重解析。而且,代码复杂度是一样的,不管你是用Jackson还是Gson。在 Jackson 中,您的代码将读取 `MyObject obj = new ObjectMapper().readValue(a_json_string, MyObject.class);`,除了类名 `Gson` 与 `ObjectMapper` 的长度不同,这实际上没有区别。 (5认同)
  • 问题是“如何转换 org.json.JSONObject -&gt; POJO”。你的回答是关于“使用 Gson 有多有趣”。 (2认同)

ara*_*nid 18

添加旧问题的答案,但......

杰克逊可以绑定到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;
}
Run Code Online (Sandbox Code Playgroud)

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

因此,它有点类似于将JSONObject转换为JsonNode的建议,但更为一般.无论它实际上是否更高效都需要进行测量:要么将JsonNode构造为中间体,要么构造TokenBuffer,这两种方式都没有开销.

  • 这是此帖子的最佳答案,谢谢分享。 (2认同)

小智 5

使用 Gson 更简单的方法。

JSONObject jsonObject = //...

PojoObject objPojo = new Gson().fromJson(jsonObject.toString(), PojoObject.class);
Run Code Online (Sandbox Code Playgroud)

这对我有用。