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 JSONObject
to 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 ObjectMapper
from 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 JSONObject
to 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.JSONObject
object) 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 readValue
method 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 convertJsonFormat
by 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 JsonNode
can represent some extra types (such as BigInteger
, Decimal
, etc) they are not necessary since the code above covers everything that JSONObject
can 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.
这对我有用。