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
How to efficiently map a org.json.JSONObject to a POJO?
提问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可以代表一些额外的类型(如BigInteger,Decimal等),它们是没有必要的,因为上面涵盖了该代码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 是一个稳定且广泛使用的库。
回答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.
这对我有用。

