1. 程式人生 > >[Jackson] 使用ObjectMapper對含有任意key的JSON進行反序列化

[Jackson] 使用ObjectMapper對含有任意key的JSON進行反序列化

使用ObjectMapper對含有任意key的JSON進行反序列化

在呼叫某個RESTful API後,返回的JSON字串中含有沒有預先定義的key,和結構固定的JSON相比,它需要一些額外的操作。

對於結構固定的JSON,使用ObjectMapper結合某個預先定義的實體型別可以非常方便地完成反序列化工作,比如對下面這樣的JSON:

GET /person/1

{
    "id": "1",
    "name": "dm_vincent",
    "age": "28"
}

結合一個實體型別,可以很輕鬆的完成反序列化工作:

public class Person {
    public
long id; public String name; public int age; }
public static <T> T getEntity(String jsonString, Class<T> prototype) {

    ObjectMapper objectMapper = new ObjectMapper();
    try {
      return (T) objectMapper.readValue(jsonString, prototype);
    } catch (IOException e) {
      e.printStackTrace();
    }

    return
null; }

但是在某些支援一次性獲取多條記錄的API中,就出現問題了。比如擁有下面這種格式的API:

GET /person/1,2,3

{
    "dm_vincent": {
        "id": "1",
        "name": "dm_vincent",
        "age": "28"
    },
    "dm_vincent2": {
        "id": "2",
        "name": "dm_vincent2",
        "age": "29"
    },
    "dm_vincent3": {
        "id
": "3", "name": "dm_vincent3", "age": "30" }
}

雖然需要獲取的實體型別還是那個Person類,可是這個時候就不像上面那樣簡單明瞭了。比如下面這段程式碼在反序列化的時候會出現問題:

public class PersonWrapper {
    public Map<String, Person> persons;
}

我們的意圖是明確的,將返回的多個Person實體物件放到一個Map結構中。但是問題就在於返回的JSON中的keys是不固定的(比如上述JSON中的keys是人名),這導致反序列化失敗。畢竟預設配置下的ObjectMapper也沒有聰明到這種程度,能夠猜測你是想要將多個實體放到Map中。

正確的做法之一是使用ObjectMapper的readTree方法:

public static <T> EntityWrapper<T> getEntityWrapper(String jsonString, Class<T> prototype) {
    ObjectMapper objectMapper = new ObjectMapper();
    EntityWrapper<T> wrapper = new EntityWrapper<T>();
    try {
      JsonNode root = objectMapper.readTree(jsonString);
      Iterator<Entry<String, JsonNode>> elements = root.fields();

      while (elements.hasNext()) {
        Entry<String, JsonNode> node = elements.next();
        String key = node.getKey();
        T element = objectMapper.readValue(node.getValue().toString(), prototype);
        wrapper.addEntry(key, element);
      }

      return wrapper;
    } catch (IOException e) {
      e.printStackTrace();
    }

    return null;
  }

簡單解釋一下上述程式碼:

使用root.field()方法能夠得到返回的JSON中的所有key-value對。
然後迴圈提取某個鍵值對的key和value,對於value我們可以直接使用之前的策略進行反序列化,因為這部分的結構也是固定的。

忽略不需要的欄位

有時候,返回的JSON字串中含有我們並不需要的欄位,那麼當對應的實體類中不含有該欄位時,會丟擲一個異常,告訴你有些欄位沒有在實體類中找到。解決辦法很簡單,在宣告ObjectMapper之後,加上上述程式碼:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);