- 簡但且方便的JSON解析,以及與Java對象的相互轉換。
- 通過注釋(annotations)和配置(settings)可擴展的配置性。
- 超快的基于流的解析性能,以及完整的數據綁定。
但許多其他Java的JSON庫僅考慮方便性和配置性,性能反倒不是面向用戶的最重要層面。
那么,為何Java開發人員不選擇Jackson而放棄其競爭產品呢?
以上功能的簡短列表其實不過是Jackson功能的冰山一角。 的確,這三個常見功能是重要的,但某種程度上也僅是最基本的東西,起碼,JSON處理器應被作為值得考慮的工具使用。除此之外,還有很多很多功能應該提供,而這也正是Jackson具備的能力。
因此,讓我們來看看7個樣例 -- 吉祥的數字 -- "殺手锏" --Jackson近年來領先競爭對手的幾點,依據先后順序介紹(始于1.0版,最新的一個特性是1.6版加入的)。
1.多處理模式,且可很好協作
從基本開始,有多種方法來使用和生產JSON數據,盡管多數JSON包僅提供單一的處理方式,但卻有三種互補的JSON處理方式(詳細解釋見:There are Tree ways...):
- 增量解析及生成(流模式)。高性能,低開銷的順序訪問。這是最低級的處理方法,相當于用于處理XML的SAX和StAX API。所有包裝內部必須有這樣的分析器,但并非所有都公開。
- 基于樹的數據模式(JSON DOM)。 樹是一種描述JSON內容的自然的概念模型,因此許多軟件包提供將JSON作為邏輯樹處理的功能。這是一個靈活的模式,可很好適用某類任務,原型處理或即席訪問也相當杰出。
- 數據綁定(JSON 與POJO相互轉換。極為方便,通常較樹狀模式更高的存取效率,也是適于Java開發人員通用的自然的數據綁定方式。常用于大多數Java REST框架,諸如JAX-RS。
盡管多角度的好處顯而易見,且各自提供最佳的用例,很少有(如果有的話?)其他的Java JSON包提供這些規范的處理模式。
大多數只提供一個模式(org.json以樹組織數據; Gson實現了數據綁定)。 Jackson提供所有模式,所有模式完全支持,且最棒的是,它很容易在兩種模式之間轉換,混合和適配。 例如,處理非常大的JSON流時,通常始于流解析,而使用數據綁定器將子數據段綁定到Java對象:這允許處理巨大的文件而沒有過多的內存占用,但卻提供 完整便利的數據綁定能力。
2. 可使用任何構造及工廠方法(不只是默的零參方法)
大多數數據(對JSON和XML)綁定工具需要一個定義和無參數的構造函數,實例化Java對象,并通過setter設置屬性或直接訪問字段。 不幸的是它使人們難以利用用“不可變對象”模式,也不同于正常代碼中的訪問模式。
Jackson thinks that developers deserve ability to specify whatever constructor or factory methods they want for instantiation; just annotate thing you want like so:Jacson認為,開發者應該能夠指定他們想為實例化的任何工廠或構造方法,只要你喜歡,注釋即可:
public class MyBean {
private final int value;
@JsonCreator
public MyBean(@JsonProperty("value") int v) {
this.value = v;
}
public int getValue() { return value; }
}
而你可以這樣定義POJO,JSON處理的情況下也無妨。(Jackson處理不可變對象的信息,可見: 博客條目 )
3. 不僅是注解,可以混合式注解!
雖然有很多好處,利用Java注解定義元數據(如類型安全、編譯時檢查,消除單獨的XML配置,DTY原則等),但也有缺點:如明顯的是,添加注解須能修改類。 而你通常不能(也不應該)修改第三方庫的代碼,至少不只是JSON序列化配置方面。
但是,如果你只可以松散動態關聯注釋,而不是嵌入在代碼中?我認為這是個了不起的想法,不管你對Jackson的混合式注解了解多少:您可以將注釋與目標類關聯(聲明為代理接口或類的一部分)目標類的處理方式如同目標類本身聲明的注解一樣。
要了解更多信息,請閱讀“ 使用混合式注解實現重用、解耦 ”。
4. 完全支持泛型類型
現在,泛型是Java開發的完整組成部分,然而,并非所有的JSON庫支持泛型,甚至在處理非常復雜的數據類型時會出錯。
以下列泛型為例:
public class Wrapper<T> { public T value; } public class ListWrapper<E> extends Wrapper<List<E>> { }
若需反序列化這些類型的數據,代碼如下:
ListWrapper<Integer> w = objectMapper.readValue("[{\"value\":13},{\"value\":7}]", new TypeReference<ListWrapper<Integer>>() { } );
Jackson在弄清必要的東西及生成期望的值方面有點小麻煩,但卻是支持泛型(或更多)的僅有的Java包。
5. 多態類型
下面是另一個factoid:繼承和多態類型可用于面向對象開發的很好方法,但也是任意實現數據綁定功能的系統的PITA。
ORM(如Hibernate)大部分的復雜性是由于沿繼承層次結構扁平化和非扁平化數據功能的需要,同樣適用于像JAXB的數據序列化包。這也就難怪,當時,只有極少數的Java包支持多態類型的JSON反序列化,大多數需要用戶建立應用代碼顯式進行類型解析。
杰克遜怎么樣? Jackson 不僅支持自動序列化和反序列化動態和多態類型,它試圖盡力把它做好。具體來說,沒有必要公開Java類名(這是其它JSON包支持多態的唯一機制)作為類 型信息 - 盡管,人們可以,它是可配置 - 但可以使用邏輯類型名稱(通過注解,或注冊實現配置)。不管采用什么類型的標識符,包含的方法也可以配置(這很好,因為極大地簡化了JSON格式)。所有 這一切都與合理的缺省功能,具有上下文適用性(這意味著你也可以定義不同類型的設置!)。
關于Jackson如何處理多態,詳見: "Jackson 1.5: 多態類型處理"。
6. 物化接口 (even less monkey code to write!)
盡管支持多態類型是強大的功能 -- 但卻存在固有的充足的復雜性 -- 這里是簡化事情的方式:物化接口(或抽象類)。.
給定接口如下:
public interface Bean { public int getX(); public void setX(int value); }
你可能想跳過這一步“Bean接口實現,包含兩倍代碼的類”,而直接處理:
Bean bean = objectMapper.readValue(json, Bean.class);
(不收你200元...呃,書寫10行代碼的猴子 - 注意,那就是,我們可以省略接口中的'setX();Bean先生很聰明,知道一些方法需要注入值)。
只有一行配置,便可實現這神奇的功能(又稱“Bean先生”)。更多關于物化接口的信息參見“ 物化接口信息“。
.我還沒有找到一個愿寫這些接口實現的編碼人員,因此,如果尋找Jackson的單一功能亮點,那就是它了。
7. 支持父/子引用(一對多,ORM)
經過前面的通用功能集,我們總結的東西更為具體:能夠干凈地處理循環類型的某些子集,成為父/子鏈接。 這些都是互相緊密耦合的引用,其中兩個對象以層次結構的方式交叉引用,如父/子樹節點的關聯, 或更常見的,ORM采用的表間連接(join)的描述。
對引用問題(或更普遍的,循環引用),JSON沒有處理它們的自然方法。,不像Java對象,沒有標識信息可用。
常用的解決方法是只標記一個被忽略的引用(Jackson可通過使用@ JsonIgnore注解實現),但其缺點是反序列化時會丟失實際的耦合目標。
Jackson 有簡單的基于注解的解決該問題的方案:兩個引用需要一個注解(對“子”連接作@JsonManagedReference注解,對“父”或“返回”連接作 @JsonBackReference注解),并在此基礎,Jackson知道要省略反向引用的序列化,但反序列化對象時要恢復它。此方式適用于典型的 ORM用例。
8. 這是全部嗎,有何異議?
實際上,Jackson的一些特性并未包含在本文中,若如此,請指正!
posted on 2012-09-06 16:47
SIMONE 閱讀(8325)
評論(1) 編輯 收藏 所屬分類:
JAVA