通俗的來說,Jackson是一個 Java 用來處理 JSON 格式數據的類庫,其性能非常好。本文就來針對Jackson的用法做一個較為詳細的實例分析。具體如下:
一、簡介
Jackson具有比較高的序列化和反序列化效率,據測試,無論是哪種形式的轉換,Jackson > Gson > Json-lib,而且Jackson的處理能力甚至高出Json-lib近10倍左右,且正確性也十分高。相比之下,Json-lib似乎已經停止更新,最新的版本也是基于JDK15,而Jackson的社區則較為活躍。
下面,結合實例來對Jackson的用法進行簡單介紹。
二、使用
Jackson提供了很多類和方法,而在序列化和反序列化中使用的最多的類則是ObjectMapper這個類,此類比較類似于Json-lib中JsonObject和ArrayObject。此類中提供了readTree(),readValue(),writeValueAsString()等方法用于轉換。具體關于此類的說明文檔地址是:http://jackson.codehaus.org/1.7.9/javadoc/org/codehaus/jackson/map/ObjectMapper.html。
為了避免重復描述,下面中所涉及到的objectMapper均是來至于ObjectMapper objectMapper = new ObjectMapper()。下面將按照序列化和反序列化兩個方面來簡單介紹用法。
1.序列化
① 對java自帶類進行序列化
測試例子
1
2
3
4
|
List list= new ArrayList(); list.add( 1 ); list.add( 2 ); list.add( 3 ); |
實現序列化:
1
2
|
String teststringlist=objectMapper.writeValueAsString(list); System.out.println(teststringlist); |
在控制臺輸出的結果是:
1
|
[ 1 , 2 , 3 ] |
結論:
Jackson對一般類型的序列化是能簡單實現的。
②對自定義類的序列化
測試例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class student { private int age= 10 ; private String name= "hhh" ; public String[] list={ "hao" , "haouhao" , "keyi" }; public Date time= new Date(); public int getAge() { return age; } public void setAge( int age) { this .age = age; } public String getName() { return name; } public void setName(String name) { this .name = name; } } |
為使例子更具有通用性,此類中包含了值類型int,引用類型String,String[],還包含了日期類型Date。
實現序列化
1
2
3
|
student st= new student(); String teststringstu=objectMapper.writeValueAsString(st); System.out.println(teststringstu); |
在控制臺輸出的結果是:
1
|
{ "list" :[ "hao" , "haouhao" , "keyi" ], "time" : 1375429228382 , "name" : "hhh" , "age" : 10 } |
結論:
通過輸出,可見轉換得到的Json串是符合格式的。但是,時間的表示有點不符合標準。下面將介紹對時間格式的修改。
③對時間格式的定義
Jackson有自己的默認時間格式,即timestamps形式,其效果即如上結果所顯示的(例如:1375429228382)。如果想設置此格式是無效,通過
1
|
objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false ) |
便可設置,這樣將使時間生成使用所謂的使用 [ISO-8601 ]-compliant notation, 輸出類似如下格式的時間: "1970-01-01T00:00:00.000+0000"。
當然,也可以自定義輸出的時間格式。
自定義時間格式的實現
例子還采用上面所介紹的student類。
1
2
3
4
5
|
student st= new student(); java.text.DateFormat myFormat = new java.text.SimpleDateFormat( "yyyy-MM-dd hh:mm:ss" ); objectMapper.getSerializationConfig().setDateFormat(myFormat); String teststringstu=objectMapper.writeValueAsString(st); System.out.println(teststringstu); |
控制臺上輸出的記過是:
1
|
{ "list" :[ "hao" , "haouhao" , "keyi" ], "time" : "2013-08-02 03:48:20" , "name" : "hhh" , "age" : 10 } |
結論:
可見時間輸出格式變成了我們想要的了。在Jackson中定義時間輸出格式的方法比在Json-lib中對時間格式的定義簡便很多。
④ 另一種序列化方法
實現序列化
所用例子依然是之前的student類。
1
2
3
4
|
student st= new student(); JsonGenerator jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(System.out, JsonEncoding.UTF8); jsonGenerator.writeObject(st); System.out.println(); |
控制臺上的輸出結果是:
1
|
{ "list" :[ "hao" , "haouhao" , "keyi" ], "time" : 1375429228382 , "name" : "hhh" , "age" : 10 } |
結論:
此方法同樣可以得到上面方法的值。但是注意此方法中的這個函數:createJsonGenerator(),它需要兩個參數,一個是OutputStream類型參數,一個是JsonEncoding類型參數。通過這兩個參數,我們可以了解到,此方法不僅可以將Json直接寫入網絡流,還可以將Json寫入文件流或者內存流。所以用途更廣。
2. 反序列化
①一次性反序列化
此方法中主要利用ObjectMapper提供的<testJsonClass> readValue(String content, Class<testJsonClass> valueType)方法。此方法需要輸入Json串以及對應的需要填充的類的Class,返回填充后的類。
將Json串解析到自定義類中
當Json串為:
1
|
String test1= "{" objectID ":357," geoPoints ":[{" x ":504604.59802246094," y ":305569.9150390625}]}" |
的時候。
首先自定義一個類:
1
2
3
4
5
|
public class testJsonClass { public int objectID; public List geoPoints= new ArrayList(); } |
然后利用下面段代碼將Json反序列化到此類中:
1
|
testJsonClass testClass= objectMapper.readValue(test1, testJsonClass. class ); |
利用
1
2
|
System.out.println(testClass.objectID); System.out.println(testClass.geoPoints) |
可以在控制臺上看到輸出的值為:
1
2
|
357 [{x= 504604.59802246094 , y= 305569.9150390625 }] |
將Json串反序列化到系統自帶的類中
當Json串是
1
|
String json = "{" error ":0," data ":{" name ":" ABC "," age ":20," phone ":{" home ":" abc "," mobile ":" def "}," friends ":[{" name ":" DEF "," phone ":{" home ":" hij "," mobile ":" klm "}},{" name ":" GHI "," phone ":{" home ":" nop "," mobile ":" qrs "}}]}," other ":{" nickname ":[]}}" 。 |
用系統自帶的Map定義一個變量:Map<String, Map<String, Object>> maps。然后利用maps = objectMapper.readValue(json, Map.class)便可將Json反序列化到變量maps中。
通過
1
2
|
System.out.println(maps.get( "error" )); System.out.println((Object)(maps.get( "data" ).get( "phone" ))) |
可在控制臺中得到下面的結果:
1
2
|
0 {home=abc, mobile=def} |
②漸次反序列化
此方法更靈活,可以只將用戶感興趣的Json串信息值提取出來。主要利用ObjectMapper提供的readTree和Jackson提供的JsonNode類來實現。
測試例子
1
|
String test= "{" results ":[{" objectID ":357," geoPoints ":[{" x ":504604.59802246094," y ":305569.9150390625}]},{" objectID ":358," geoPoints ":[{" x ":504602.2680053711," y ":305554.43603515625}]}]}" ; |
此Json串比較復雜,包含了嵌套數組的形式,具有通用性。
實現反序列化
1
2
3
4
5
6
7
8
9
10
11
|
JsonNode node= objectMapper.readTree(test); //將Json串以樹狀結構讀入內存 JsonNode contents=node.get( "results" ); //得到results這個節點下的信息 for ( int i= 0 ;i<contents.size();i++) //遍歷results下的信息,size()函數可以得節點所包含的的信息的個數,類似于數組的長度 { System.out.println(contents.get(i).get( "objectID" ).getIntValue()); //讀取節點下的某個子節點的值 JsonNode geoNumber=contents.get(i).get( "geoPoints" ); for ( int j= 0 ;j<geoNumber.size();j++) //循環遍歷子節點下的信息 { System.out.println(geoNumber.get(j).get( "x" ).getDoubleValue()+ " " +geoNumber.get(j).get( "y" ).getDoubleValue()); } } |
在控制臺下輸出的結果是:
1
2
3
4
|
357 504604.59802246094 305569.9150390625 358 504602.2680053711 305554.43603515625 |
結論:
此方法類似于XML解析中的DOM方式解析,其好處是結構明細,便于提取想要的信息。當然,其缺點也和此方法一樣:耗時費空間。
三.總結
Jackson關于Json的操作主要如上所示,其方法使用起來很便利,而且也很靈活,即提供了一次性完成的操作,也提供了可以按需讀取信息的操作。并且Jackson的功能很齊全,可以對序列化和反序列化進行多種細節的控制,例如注解功能和對于Hibernate的延遲注入功能以及設置時間格式功能等,因為這些功能目前不太需要,所以仔細研究留待以后。同時,Jackson還支持對XML的一系列序列化和反序列化的操作,其思路與解析Json的大致相同。
對于Jackson目前的缺點,網上有人測試所比Json-lib更占內存一些。而利用空間換時間,一般是值得的。