簡體   English   中英

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

[英]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 ) - 然后從一種表示到另一種表示的轉換將使您免於解析-序列化-解析過程。 因此,不是使用接受StringreadValue方法,而是使用接受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可以表示一些額外的類型(例如BigIntegerDecimal等),但它們不是必需的,因為上面的代碼涵蓋了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 是一個穩定且廣泛使用的庫。

請參閱https://code.google.com/p/google-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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM