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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20534862/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 02:35:29  来源:igfitidea点击:

How to efficiently map a org.json.JSONObject to a POJO?

javajsonmappingHymansonmapper

提问by Daniel S.

This question must have been asked before, but I couldn't find it.

这个问题以前肯定有人问过,但我找不到。

I'm using a 3rd party library to retrieve data in JSON format. The library offers the data to me as a org.json.JSONObject. I want to map this JSONObjectto a POJO (Plain Old Java Object)for simpler access/code.

我正在使用第 3 方库以 JSON 格式检索数据。图书馆将数据作为org.json.JSONObject. 我想将它映射JSONObject到一个POJO(Plain Old Java Object)以便更简单的访问/代码。

For mapping, I currently use the ObjectMapperfrom the Hymanson library in this way:

对于映射,我目前ObjectMapper以这种方式使用来自 Hymanson 库的 :

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

To my understanding, the above code can be optimized significantly, because currently the data in the JSONObject, which is already parsed, is again fed into a serialization-deserialization chain with the JSONObject.toString()method and then to the ObjectMapper.

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

I want to avoid these two conversions (toString()and parsing). Is there a way to use the JSONObjectto map its data directly to a POJO?

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

采纳答案by mgibsonbr

Since you have an abstract representation of some JSON data (an org.json.JSONObjectobject) and you're planning to use the Hymanson library - that has its own abstract representation of JSON data (com.fasterxml.Hymanson.databind.JsonNode) - then a conversion from one representation to the other would save you from the parse-serialize-parse process. So, instead of using the readValuemethod that accepts a String, you'd use this versionthat accepts a JsonParser:

由于您有一些 JSON 数据(一个org.json.JSONObject对象)的抽象表示,并且您计划使用 Hymanson 库——它有自己的 JSON 数据抽象表示 ( com.fasterxml.Hymanson.databind.JsonNode)——那么从一种表示到另一种表示的转换将使您免于解析-序列化-解析过程。因此,而不是使用readValue接受的方法String,你会使用这个版本,它接受一个JsonParser

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

JSON is a very simple format, so it should not be hard to create the convertJsonFormatby hand. Here's my attempt:

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

Note that, while the Hymanson's JsonNodecan represent some extra types (such as BigInteger, Decimal, etc) they are not necessary since the code above covers everything that JSONObjectcan represent.

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

回答by Stephane Lallemagne

If you're not tied with Hymanson, you can use the handy google-gson library as an alternative. It requires only one jar and is very simple to use:

如果您与 Hymanson 没有关系,您可以使用方便的 google-gson 库作为替代。它只需要一个 jar 并且使用起来非常简单:

Converting a java object into a JSON string:

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

  String json_string = new Gson().toJson(an_object);

Creating a java object from a JSON string:

从 JSON 字符串创建一个 java 对象:

  MyObject obj = new Gson().fromJson(a_json_string, MyObject.class);

I dont't know about performance compared to Hymanson, but it's hard to be simpler than this... Gson is a stable and widely used library.

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

See https://code.google.com/p/google-gson/

请参阅https://code.google.com/p/google-gson/

回答by araqnid

Adding an answer to an old question, but...

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

Hymanson can bind to/from the org.json types. In general it can convert between any types that it can bind to, by effectively(although not actually) serializing to JSON and deserializing.

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

If you have the JsonOrgModuleregistered, you can simply do the conversion straight from ObjectMapper:

如果您注册了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;
}

I mentioned that this is effectivelyserialising? That's true, it serializes the input object into a TokenBuffer, which represents a stream of JSON parsing events, but with less impact of building strings etc., as it can largely reference data from the input. It then feeds this stream to a deserializer to produce the output object.

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

So, it's somewhat similar to the suggestion to convert the JSONObject to a JsonNode, but much more general. Whether it's actually more efficient or not would need measuring: either you construct a JsonNode as an intermediate or a TokenBuffer, neither way is without overhead.

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

回答by Pradipkumar Ahire

More simple way by using Gson.

使用 Gson 更简单的方法。

JSONObject jsonObject = //...

PojoObject objPojo = new Gson().fromJson(jsonObject.toString(), PojoObject.class);

This worked for me.

这对我有用。