2015-12-03 32 views
2

我有一個看起來像這樣的對象:從LinkedHashMap中檢索值

{ 
/test1: { 
    get: { 
    tags: [ 
    "restcalls" 
    ] 
} 
}, 
/test2: { 
    put: { 
    tags: [ 
    "restcalls" 
    ] 
} 
} 
} 

我檢索上述目的是這樣的:

HashMap<?, ?> json = new ObjectMapper().readValue(str, HashMap.class); 

但什麼是檢索tags的最佳途徑,用其他關鍵字替換它們可以說"my rest calls"。請注意,get,put可以是任何其他變量名稱,所以它的動態但標籤將始終處於獲取,放置狀態。

+0

不要使用'HashMap'。使用'TreeNode'並適當地遍歷它。 –

+0

你能提供一個例子,爲什麼TreeNode? – fscore

+0

由於您已經在使用對象映射器來轉換JSON,爲什麼不將每個測試對象轉換爲一個真正的「TestObject」POJO,該對象持有'Method'對象,該對象包含一組標記?遍歷複雜的對象圖將來可能無法維護。我使用Commons BeanUtils(http://commons.apache.org/proper/commons-beanutils)將對象從一種類型轉換爲另一種類型,如果您願意,我很樂意提供一個示例。 – johnnieb

回答

3

您已經選擇Jackson作爲Java的JSON庫(,我可以說是一個不錯的選擇),這樣的問題在你的手是如何利用傑克遜遍歷和更新JSON的最佳方式,但那些誰甚至決定其Java的JSON庫使用可以讀取here其中比較下面提到7 Java的JSON庫。以下是結論摘自鏈接:

作爲結論,如果你知道你要使用只在您的應用程序數據的小 量以及要存儲或讀給 和JSON格式,你應該考慮使用Flexjson或GSON。如果您 要使用大量數據,並希望存儲或讀取 它和JSON格式,你應該考慮使用傑克遜或 JSON-lib的

  • 傑克遜
  • 谷歌,GSON
  • JSON-lib的
  • Flexjson
  • JSON-io的
  • genson
  • JSONiJ


傑克遜

最重要的是要明白的是,傑克遜提供了處理JSON(閱讀更多here),所以適當的方法應該是明智的選擇考慮的具體要求三種可供選擇的方法。

  1. 流API又名 「增量解析/生成」):它的讀取和寫入JSON含量爲離散事件。 最好的情況使用:遍歷事件(或令牌)流。類似於: SAX和斯塔克斯

  2. 樹模型:它提供了一個JSON文檔的一個可變的內存樹表示。樹模型與XML DOM類似。 最佳案例使用:將Json數據綁定到Java對象中。 類似於: JAXB

  3. 數據綁定:它轉換JSON和從或者基於屬性訪問公約或註釋的POJO。有兩種變體:簡單和完整的數據綁定。 最佳情況下使用:構建的樹結構(從JSON)和使用合適的方法遍歷它。 類似於: DOM

    • 簡單數據綁定手段轉化和Java地圖,列表,字符串,數字,布爾和空
    • 全部數據綁定意味着轉換和從任何的Java bean類型(以及上面提到的 「簡單」 類型)

通常使用「樹模型」的做法被認爲是從「性能的角度看」最好的,因爲它給遍歷樹的優點。

其他選項也有自己的優勢像流API有較少的內存和CPU開銷數據綁定使用方便,因爲它提供List和JSON數據的Map表示。然而,擁有如此之多的處理能力和內存,現在真正重要的是性能。

如果你的JSON數據是巨大的,然後分析在樹表示樹是否會有更寬的寬度或長度較長。如果它具有更寬的寬度,則肯定使用「樹模型」將有一棵樹處理相關的性能優勢(確保你在塊的映射,而不是全部的東西一次性)。但是,如果樹是冗長的,意義不具有良好的寬度,但就像是一個很長的尾巴,那麼可以考慮使用「流API」,因爲在這種情況下樹處理的優勢無法得到證實。如果數據很小,那麼它幾乎不重要,您可以使用「樹模型」作爲默認值。

當前您正在使用「數據綁定」方法,但建議使用「樹模型」,因爲您只需要遍歷和操縱JSON。看看你給出的信息,看起來你不需要將你的JSON轉換成Java對象,所以「數據綁定」方法看起來是一個壞主意。

傑克遜樹模型

傑克遜com.fasterxml.jackson.databind.JsonNode形式傑克遜的樹模型的基礎。 想想傑克遜的樹模型作爲HTML文檔的DOM的,方式DOM表示樹結構完整的HTML文檔,傑克遜的樹模型代表在樹上晶格結構完整的JSON字符串。

下面是代碼,這將有助於您使用傑克遜的樹模型,實現你在找什麼:

import java.io.IOException; 
import java.util.Iterator; 

import com.fasterxml.jackson.core.JsonProcessingException; 
import com.fasterxml.jackson.databind.JsonNode; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import com.fasterxml.jackson.databind.node.ObjectNode; 


public class Test { 

    public static void main(String[] args) throws JsonProcessingException, IOException { 
     String jsonString = "{\"test1\": {\"get\": {\"tags\": [\"restcalls1\"]}}, \"test2\": {\"put\": {\"tags\": [\"restcalls2\"] }}}"; 
     ObjectMapper objectMapper = new ObjectMapper(); 
     JsonNode rootNode = objectMapper.readTree(jsonString); 

     Iterator<JsonNode> iterator2 = rootNode.iterator(); 
     while (iterator2.hasNext()) { 
      JsonNode node2 = iterator2.next().findParent("tags"); 
      ObjectNode objectNode = (ObjectNode) node2; 
      objectNode.putArray("tags").add("my rest calls"); 
     } 

     Iterator<JsonNode> iterator = rootNode.iterator(); 
     while (iterator.hasNext()) { 
      JsonNode node2 = iterator.next(); 
      System.out.println(node2); 
     } 

    } 
} 

樹模型的優點:

閱讀here更多細節

  • 如果Json內容的結構非常不規則,可能很難(或不可能)找到或創建等價的Java對象結構。樹模型可能是唯一的實際選擇。
  • 用於顯示任何JSON內容。 樹模型是內部訪問和操作的自然選擇。
  • 由於我們不需要特定的Java對象進行綁定,所以編寫的代碼可能會更少。

進一步閱讀:


基於OP公司的C omment:

下面的代碼顯示瞭如何遍歷和打印整個JSON。通過這種方式,您可以遍歷整個JSON,然後訪問您正在查找的元素。主要想說明的是,你需要知道該元素的名稱,即使您使用流API的方式,然後你也應該知道要尋找的元素名稱,請參見流API例如here

在任何情況下,你可以隨時選擇遍歷整個JSON(如示出的例子在下文中),或者做具體和直接操作(如圖所示實施例中上面)

package com.him.services; 

import java.io.IOException; 
import java.util.ArrayList; 
import java.util.Iterator; 

import com.fasterxml.jackson.core.JsonProcessingException; 
import com.fasterxml.jackson.databind.JsonNode; 
import com.fasterxml.jackson.databind.ObjectMapper; 


public class Test { 

    public static void main(String[] args) throws JsonProcessingException, IOException { 
     jacksonTest(); 
    } 

    private static void jacksonTest() throws JsonProcessingException, IOException { 
     String jsonString = "{\"test1\": {\"get\": {\"tags\": [\"restcalls1\"]}}, \"test2\": {\"put\": {\"tags\": [\"restcalls2\"] }}}"; 
     ObjectMapper objectMapper = new ObjectMapper(); 
     JsonNode rootNode = objectMapper.readTree(jsonString); 
     ArrayList<JsonNode> nodeList = new ArrayList<JsonNode>(); 
     nodeList.add(rootNode); 

     printCompleteJson(nodeList); 
    } 

    private static void printCompleteJson(ArrayList<JsonNode> rootNode) throws IOException { 
     for (int i = 0; i < rootNode.size(); i++) { 
      Iterator<JsonNode> iterator = rootNode.get(i).iterator(); 
      JsonNode node = null; 
      ArrayList<JsonNode> nodeList = new ArrayList<JsonNode>(); 
      boolean isEmpty = true; 
      while (iterator.hasNext()) { 
       isEmpty = false; 
       node = iterator.next(); 
       nodeList.add(node); 
       System.out.println(node); 
      } 
      if(isEmpty){ 
       return; 
      } 
      printCompleteJson(nodeList); 
     } 
    } 
} 
+0

但是'get','put'可以是任何HTTP動詞,所以我不想明確指定要檢索值但自動檢測它。 – fscore

+0

我試圖給你更多關於核心概念的內容,這樣一旦你抓住了概念,這樣的小調整或需求變化就不應該成爲問題。我編輯了我的答案以解決您的疑慮。如有任何問題,請讓我知道。基本上你應該明白,用多少種不同的方法可以使用傑克遜或其他圖書館來實現同樣的事情。所有你需要的是採取一種方法和閱讀它的文檔,讓自己意識到可用的API,然後你可以用它來實現你的需求。 – hagrawal

+0

它怎麼樣,你有任何問題嗎? – hagrawal

0

您可以使用傑克遜的JsonNode類遍歷整個JSON和更改標籤的節點值。請參見下面的代碼:

public class Tags { 

    public static void main(String[] args) throws Exception { 
     InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("tags.json"); 
     ObjectMapper om = new ObjectMapper(); 
     JsonNode node = om.readTree(in); 
     recursiveFind(node); 
     System.out.println(node); //Prints {"test1":{"get":{"tags":["my rest calls"]}},"test2":{"put":{"tags":["my rest calls"]}}} 
    } 

    private static void recursiveFind(JsonNode node) { 
     if (!node.isObject()) { 
      return; 
     } 

     JsonNode tags = node.get("tags"); 
     if (tags != null) { 
      ArrayNode arry = (ArrayNode) tags; 
      arry.removeAll(); 
      arry.add("my rest calls"); 
     } 

     Iterator<JsonNode> it = node.elements(); 
     while (it.hasNext()) { 
      JsonNode jsonNode = it.next(); 
      recursiveFind(jsonNode); 
     } 
    } 
}