[英]How to efficiently map a org.json.JSONObject to a POJO?
這個問題以前肯定有人問過,但我找不到。
我正在使用第 3 方庫以 JSON 格式檢索數據。 該庫將數據作為org.json.JSONObject
提供給我。 我想將此JSONObject
映射到POJO(Plain Old Java Object),以便更簡單地訪問/代碼。
對於映射,我目前以這種方式使用 Jackson 庫中的ObjectMapper
:
JSONObject jsonObject = //...
ObjectMapper mapper = new ObjectMapper();
MyPojoClass myPojo = mapper.readValue(jsonObject.toString(), MyPojoClass.class);
根據我的理解,上面的代碼可以得到顯着優化,因為當前JSONObject
中已經解析的數據再次通過JSONObject.toString()
方法輸入到序列化-反序列化鏈中,然后再輸入到ObjectMapper
。
我想避免這兩個轉換( toString()
和解析)。 有沒有辦法使用JSONObject
將其數據直接映射到 POJO?
由於您有一些 JSON 數據的抽象表示(一個org.json.JSONObject
對象),並且您計划使用 Jackson 庫 - 它有自己的 JSON 數據抽象表示( com.fasterxml.jackson.databind.JsonNode
) - 然后從一種表示到另一種表示的轉換將使您免於解析-序列化-解析過程。 因此,不是使用接受String
的readValue
方法,而是使用接受JsonParser
這個版本:
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
可以表示一些額外的類型(例如BigInteger
、 Decimal
等),但它們不是必需的,因為上面的代碼涵蓋了JSONObject
可以表示的所有內容。
如果您與 Jackson 沒有關系,您可以使用方便的 google-gson 庫作為替代。 它只需要一個 jar 並且使用起來非常簡單:
將 java 對象轉換為 JSON 字符串:
String json_string = new Gson().toJson(an_object);
從 JSON 字符串創建一個 java 對象:
MyObject obj = new Gson().fromJson(a_json_string, MyObject.class);
我不知道與 Jackson 相比的性能,但很難比這更簡單...... Gson 是一個穩定且廣泛使用的庫。
添加一個舊問題的答案,但是......
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,這兩種方法都沒有開銷。
使用 Gson 更簡單的方法。
JSONObject jsonObject = //...
PojoObject objPojo = new Gson().fromJson(jsonObject.toString(), PojoObject.class);
這對我有用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.