2012-11-20 37 views
9

我有一個可以有多種類型的JSON文件。使用流/對象方法將JSON解析爲Jackson

例如:

{ 
    "dog": { 
     "owner" : "John Smith", 
     "name" : "Rex", 
     "toys" : { 
      "chewtoy" : "5", 
      "bone" : "1" 
     } 
    }, 
    "person": { 
     "name" : "John Doe", 
     "address" : "23 Somewhere Lane" 
    } 
    // Further examples of dogs and people, and a few other types. 
} 

我想這些解析爲對象。即。我想創建一個擁有所有者/名稱/玩具屬性的Dog對象,以及具有名稱/地址屬性的人員,並使用Jackson來讀取並創建對象。

排序很重要 - 例如,我需要知道Rex出現在John Doe之前。我更喜歡使用類似流的方法(即將雷克斯閱讀並解析爲Dog對象,對其進行處理,然後丟棄它,然後轉到John Doe)。所以我需要一個基於流的方法。

我不知道如何使用流讀取API(按順序通過)和ObjectMapper接口(爲了創建JSON的Java對象)來完成此操作。

+1

(1)您對流或類SAX解析的問題完全有效。 +1。但是(2)如果您在字典中訂購事宜,您的數據設計得不好。 JSON字典本質上是無序的。如果您需要訂單,請使用數組並將類型(狗/人)信息作爲屬性進行編碼。 –

+0

嗯。數據源可能不可更改(不受我控制)。當你說使用數組並對信息進行編碼時,你的意思是手動執行此操作嗎? (通讀所有令牌並創建適當的對象來調用適當的setter)或者有沒有辦法使用Jackson做到這一點? –

+0

我的意思是說,如果訂單很重要,那麼JSON數據應該以數組的形式出現,而每種對象都使用不同的編碼類型。但是,如果您不控制JSON數據,那麼就不會想到 - 您必須按照您的建議處理流解析。 :)我沒有你的實際問題的答案,雖然其他人肯定會這樣做。但要知道,想出這種JSON格式的人正在玩火。依靠字典中的鍵的順序是非常脆弱的,不要說它爲正在嘗試處理它的人(你)創造的屁股疼痛 - 它違背了大多數工具的五穀。 –

回答

10

要做到這一點,你需要使用一個對象映射器與貴廠

import org.codehaus.jackson.JsonFactory; 
import org.codehaus.jackson.JsonParser; 
import org.codehaus.jackson.JsonProcessingException; 
import org.codehaus.jackson.map.ObjectMapper; 
... 
private static ObjectMapper mapper = new ObjectMapper(); 
private static JsonFactory factory = mapper.getJsonFactory(); 

然後建立輸入解析器。現在

JsonParser parser = factory.createJsonParser(in); 

你可以混合到parser.nextToken()呼叫及parser.readValueAs(C類)。下面是一個從地圖獲取類的示例:

Map<String, Class<?>> classMap = new HashMap<String, Class<?>>(); 
classMap.put("dog", Dog.class); 
classMap.put("person", Person.class); 

InputStream in = null; 
JsonParser parser = null; 
List<Object> results = new ArrayList<Object>(); 
try { 
    in = this.getClass().getResourceAsStream("input.json"); 
    parser = factory.createJsonParser(in); 
    parser.nextToken();// JsonToken.START_OBJECT 
    JsonToken token = null; 
    while((token = parser.nextToken()) == JsonToken.FIELD_NAME) { 
    String name = parser.getText(); 
    parser.nextToken(); // JsonToken.START_OBJECT 
    results.add(parser.readValueAs(classMap.get(name))); 
    } 
    // ASSERT: token = JsonToken.END_OBJECT 
} 
finally { 
    IOUtils.closeQuietly(in); 
    try { 
    parser.close(); 
    } 
    catch(Exception e) {} 
} 
+0

我想我現在看到了。當我最初嘗試這樣做時,我很掙扎,因爲我不知道自己在什麼對象(「狗」或「人」),但是如果數據被格式化爲具有狗/人值作爲值的數組在「類型」屬性中,我可以做到這一點。感謝大家。 –

+0

一個很好的答案。但是,如果您可以使用最新的Jackson庫重寫您的代碼片段,那將會很棒。 –