文档章节

JSON 序列化与反序列化详解(下)

侠客人生
 侠客人生
发布于 2017/07/14 22:52
字数 5837
阅读 146
收藏 0

JackSon学习教程

概述

Jackson框架是基于Java平台的一套数据处理工具,被称为“最好的Java Json解析器”。 
Jackson框架包含了3个核心库:streaming,databind,annotations.Jackson还包含了其它数据处理类库,此外不作说明。
Jackson版本: 1.x (目前版本从1.1~1.9)与2.x。1.x与2.x从包的命名上可以看出来,1.x的类库中,包命名以:org.codehaus.jackson.xxx开头,而2.x类库中包命令:com.fastxml.jackson.xxx开头

Jackson Home Page:https://github.com/FasterXML/jackson
Jackson Wiki:http://wiki.fasterxml.com/JacksonHome
Jackson doc: https://github.com/FasterXML/jackson-docs
Jackson Download Page:http://wiki.fasterxml.com/JacksonDownload

 

准备工作

本文所有程序都基于JDK1.7,依赖jackon的三个核心类库:
jackson-core-2.5.3.jar
jackson-annotations-2.5.3.jar
jackson-databind-2.5.3.jar

 

Jackson处理Json

Jackson提供了三种可选的Json处理方法:流式API(Streaming API) 、树模型(Tree Model)、数据绑定(Data Binding)。从使用角度来看,比较一下这三种处理Json的方式的特性:

Streaming API:是效率最高的处理方式(开销低、读写速度快,但程序编写复杂度高)
Tree Model:是最灵活的处理方式
Data Binding:是最常用的处理方式

下面我们通过例子程序分别使用DataBinding,TreeModel,Streaming的方式来创建和解析Json字符串

1.DataBinding处理Json

Jackson支持Java对象与Json之间的相互转化。java对象序列化为json字符串,json字符串也可以反序列化为相同的java对象。

 

(1)java对象转化成json:

Province.java

1. package com.jackson.json.databinding;  

2.   

3. public class Province {  

4.     public String name;  

5.     public int population;  

6.     public String[] city;     

7. }  

Country.java

1. package com.jackson.json.databinding;  

2.   

3. import java.util.ArrayList;  

4. import java.util.Arrays;  

5. import java.util.Date;  

6. import java.util.HashMap;  

7. import java.util.List;  

8. import java.util.Map;  

9.   

10. public class Country {  

11.     // 注意:被序列化的bean的private属性字段需要创建getter方法或者属性字段应该为public  

12.     private String country_id;  

13.     private Date birthDate;  

14.     private List<String> nation = new ArrayList<String>();  

15.     private String[] lakes;  

16.     private List<Province> provinces = new ArrayList<Province>();  

17.     private Map<String, Integer> traffic = new HashMap<String, Integer>();  

18.   

19.     public Country() {  

20.         // TODO Auto-generated constructor stub  

21.     }  

22.   

23.     public Country(String countryId) {  

24.         this.country_id = countryId;  

25.     }  

26.   

27.     public String getCountry_id() {  

28.         return country_id;  

29.     }  

30.   

31.     public void setCountry_id(String country_id) {  

32.         this.country_id = country_id;  

33.     }  

34.   

35.     public Date getBirthDate() {  

36.         return birthDate;  

37.     }  

38.   

39.     public void setBirthDate(Date birthDate) {  

40.         this.birthDate = birthDate;  

41.     }  

42.   

43.     public List<String> getNation() {  

44.         return nation;  

45.     }  

46.   

47.     public void setNation(List<String> nation) {  

48.         this.nation = nation;  

49.     }  

50.   

51.     public String[] getLakes() {  

52.         return lakes;  

53.     }  

54.   

55.     public void setLakes(String[] lakes) {  

56.         this.lakes = lakes;  

57.     }  

58.   

59.     public Integer get(String key) {  

60.         return traffic.get(key);  

61.     }  

62.   

63.     public Map<String, Integer> getTraffic() {  

64.         return traffic;  

65.     }  

66.   

67.     public void setTraffic(Map<String, Integer> traffic) {  

68.         this.traffic = traffic;  

69.     }  

70.   

71.     public void addTraffic(String key, Integer value) {  

72.         traffic.put(key, value);  

73.     }  

74.   

75.     public List<Province> getProvinces() {  

76.         return provinces;  

77.     }  

78.   

79.     public void setProvinces(List<Province> provinces) {  

80.         this.provinces = provinces;  

81.     }  

82.   

83.     @Override  

84.     public String toString() {  

85.         return "Country [country_id=" + country_id + ", birthDate=" + birthDate  

86.                 + ", nation=" + nation + ", lakes=" + Arrays.toString(lakes)  

87.                 + ", province=" + provinces + ", traffic=" + traffic + "]";  

88.     }  

89.   

90. }  

JavaBeanSerializeToJson.java

1. package com.jackson.json.databinding;  

2.   

3. import java.io.File;  

4. import java.text.SimpleDateFormat;  

5. import java.util.ArrayList;  

6. import java.util.List;  

7.   

8. import com.fasterxml.jackson.annotation.JsonInclude.Include;  

9. import com.fasterxml.jackson.databind.ObjectMapper;  

10. import com.fasterxml.jackson.databind.SerializationFeature;  

11.   

12. public class JavaBeanSerializeToJson {  

13.   

14.     public static void convert() throws Exception {  

15.         // 使用ObjectMapper来转化对象为Json  

16.         ObjectMapper mapper = new ObjectMapper();  

17.         // 添加功能,让时间格式更具有可读性  

18.         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");  

19.         mapper.setDateFormat(dateFormat);  

20.   

21.         Country country = new Country("China");  

22.         country.setBirthDate(dateFormat.parse("1949-10-01"));  

23.         country.setLakes(new String[] { "Qinghai Lake", "Poyang Lake",  

24.                 "Dongting Lake", "Taihu Lake" });  

25.   

26.         List<String> nation = new ArrayList<String>();  

27.         nation.add("Han");  

28.         nation.add("Meng");  

29.         nation.add("Hui");  

30.         nation.add("WeiWuEr");  

31.         nation.add("Zang");  

32.         country.setNation(nation);  

33.   

34.         Province province = new Province();  

35.         province.name = "Shanxi";  

36.         province.population = 37751200;  

37.         Province province2 = new Province();  

38.         province2.name = "ZheJiang";  

39.         province2.population = 55080000;  

40.         List<Province> provinces = new ArrayList<Province>();  

41.         provinces.add(province);  

42.         provinces.add(province2);  

43.         country.setProvinces(provinces);  

44.           

45.         country.addTraffic("Train(KM)", 112000);  

46.         country.addTraffic("HighWay(KM)", 4240000);  

47.         // 为了使JSON视觉上的可读性,增加一行如下代码,注意,在生产中不需要这样,因为这样会增大Json的内容  

48.         mapper.configure(SerializationFeature.INDENT_OUTPUT, true);  

49.         // 配置mapper忽略空属性  

50.         mapper.setSerializationInclusion(Include.NON_EMPTY);  

51.         // 默认情况,Jackson使用Java属性字段名称作为 Json的属性名称,也可以使用Jackson annotations(注解)改变Json属性名称  

52.         mapper.writeValue(new File("country.json"), country);  

53.     }  

54.   

55.     public static void main(String[] args) throws Exception {  

56.         convert();  

57.     }  

58.   

59. }  

程序运行后生成country.json,内容如下:

1. {  

2.   "country_id" : "China",  

3.   "birthDate" : "1949-10-01",  

4.   "nation" : [ "Han", "Meng", "Hui", "WeiWuEr", "Zang" ],  

5.   "lakes" : [ "Qinghai Lake", "Poyang Lake", "Dongting Lake", "Taihu Lake" ],  

6.   "provinces" : [ {  

7.     "name" : "Shanxi",  

8.     "population" : 37751200  

9.   }, {  

10.     "name" : "ZheJiang",  

11.     "population" : 55080000  

12.   } ],  

13.   "traffic" : {  

14.     "HighWay(KM)" : 4240000,  

15.     "Train(KM)" : 112000  

16.   }  

17. }  

 

(2)Json字符串反序列化为java对象:

1. package com.jackson.json.databinding;  

2.   

3. import java.io.File;  

4. import java.io.IOException;  

5. import java.text.SimpleDateFormat;  

6. import java.util.Iterator;  

7. import java.util.List;  

8.   

9. import com.fasterxml.jackson.core.JsonParseException;  

10. import com.fasterxml.jackson.databind.DeserializationFeature;  

11. import com.fasterxml.jackson.databind.JsonMappingException;  

12. import com.fasterxml.jackson.databind.ObjectMapper;  

13.   

14. /** 

15.  * 将Json字符串反序列化为Java对象 

16.  */  

17. public class JsonDeserializeToJava {  

18.       

19.     public static void main(String[] args) throws Exception {  

20.         //ObjectMapper类用序列化与反序列化映射器  

21.         ObjectMapper mapper = new ObjectMapper();  

22.         File json = new File("country.json");  

23.         //当反序列化json时,未知属性会引起的反序列化被打断,这里我们禁用未知属性打断反序列化功能,  

24.         //因为,例如json里有10个属性,而我们的bean中只定义了2个属性,其它8个属性将被忽略  

25.         mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);  

26.           

27.         //从json映射到java对象,得到country对象后就可以遍历查找,下面遍历部分内容,能说明问题就可以了  

28.         Country country = mapper.readValue(json, Country.class);  

29.         System.out.println("country_id:"+country.getCountry_id());  

30.         //设置时间格式,便于阅读  

31.         SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");  

32.         String birthDate = dateformat.format(country.getBirthDate());  

33.         System.out.println("birthDate:"+birthDate);  

34.           

35.         List<Province> provinces = country.getProvinces();  

36.         for (Province province : provinces) {  

37.             System.out.println("province:"+province.name + "\n" + "population:"+province.population);  

38.         }  

39.     }  

40. }  

程序运行结果:

1. country_id:China  

2. birthDate:1949-10-01  

3. province:Shanxi  

4. population:37751200  

5. province:ZheJiang  

6. population:55080000  

 

2.Tree Model处理Json

(1)tree model生成json:

1. package com.jackson.json.treemodel;  

2.   

3. import java.io.File;  

4. import java.io.FileWriter;  

5.   

6. import com.fasterxml.jackson.core.JsonFactory;  

7. import com.fasterxml.jackson.core.JsonGenerator;  

8. import com.fasterxml.jackson.databind.ObjectMapper;  

9. import com.fasterxml.jackson.databind.SerializationFeature;  

10. import com.fasterxml.jackson.databind.node.ArrayNode;  

11. import com.fasterxml.jackson.databind.node.JsonNodeFactory;  

12. import com.fasterxml.jackson.databind.node.ObjectNode;  

13.   

14. public class SerializationExampleTreeModel {  

15.       

16.     public static void main(String[] args) throws Exception {  

17.         //创建一个节点工厂,为我们提供所有节点  

18.         JsonNodeFactory factory = new JsonNodeFactory(false);  

19.         //创建一个json factory来写tree modle为json  

20.         JsonFactory jsonFactory = new JsonFactory();  

21.         //创建一个json生成器  

22.         JsonGenerator generator = jsonFactory.createGenerator(new FileWriter(new File("country2.json")));  

23.         //注意,默认情况下对象映射器不会指定根节点,下面设根节点为country  

24.         ObjectMapper mapper = new ObjectMapper();  

25.         ObjectNode country = factory.objectNode();  

26.           

27.         country.put("country_id", "China");  

28.         country.put("birthDate", "1949-10-01");  

29.           

30.         //在Java中,List和Array转化为json后对应的格式符号都是"obj:[]"  

31.         ArrayNode nation = factory.arrayNode();  

32.         nation.add("Han").add("Meng").add("Hui").add("WeiWuEr").add("Zang");  

33.         country.set("nation", nation);  

34.           

35.         ArrayNode lakes = factory.arrayNode();  

36.         lakes.add("QingHai Lake").add("Poyang Lake").add("Dongting Lake").add("Taihu Lake");  

37.         country.set("lakes", lakes);  

38.           

39.         ArrayNode provinces = factory.arrayNode();  

40.         ObjectNode province = factory.objectNode();  

41.         ObjectNode province2 = factory.objectNode();  

42.         province.put("name","Shanxi");  

43.         province.put("population", 37751200);  

44.         province2.put("name","ZheJiang");  

45.         province2.put("population", 55080000);  

46.         provinces.add(province).add(province2);  

47.         country.set("provinces", provinces);  

48.           

49.         ObjectNode traffic = factory.objectNode();  

50.         traffic.put("HighWay(KM)", 4240000);  

51.         traffic.put("Train(KM)", 112000);  

52.         country.set("traffic", traffic);  

53.           

54.         mapper.configure(SerializationFeature.INDENT_OUTPUT, true);  

55.         mapper.writeTree(generator, country);  

56.     }  

57.   

58. }  

程序运行生成country2.json,内容如下:

1. {"country_id":"China","birthDate":"1949-10-01","nation":["Han","Meng","Hui","WeiWuEr","Zang"],"lakes":["QingHai Lake","Poyang Lake","Dongting Lake","Taihu Lake"],"provinces":[{"name":"Shanxi","population":37751200},{"name":"ZheJiang","population":55080000}],"traffic":{"HighWay(KM)":4240000,"Train(KM)":112000}}  

(2) json字符串反序列化为tree mode

DeserializationExampleTreeModel1.java,请注意观察程序中不同的JsonNode的类型变化

1. package com.jackson.json.treemodel;  

2.   

3. import java.io.File;  

4. import java.util.Iterator;  

5.   

6. import com.fasterxml.jackson.databind.JsonNode;  

7. import com.fasterxml.jackson.databind.ObjectMapper;  

8.   

9. public class DeserializationExampleTreeModel1 {  

10.   

11.     public static void main(String[] args) throws Exception {  

12.         ObjectMapper mapper = new ObjectMapper();  

13.         // Jackson提供一个树节点被称为"JsonNode",ObjectMapper提供方法来读json作为树的JsonNode根节点  

14.         JsonNode node = mapper.readTree(new File("country2.json"));  

15.         // 看看根节点的类型  

16.         System.out.println("node JsonNodeType:"+node.getNodeType());  

17.         // 是不是一个容器  

18.         System.out.println("node is container Node ? "+node.isContainerNode());  

19.         // 得到所有node节点的子节点名称  

20.         System.out.println("---------得到所有node节点的子节点名称-------------------------");  

21.         Iterator<String> fieldNames = node.fieldNames();  

22.         while (fieldNames.hasNext()) {  

23.             String fieldName = fieldNames.next();  

24.             System.out.print(fieldName+" ");  

25.         }  

26.         System.out.println("\n-----------------------------------------------------");  

27.         // as.Text的作用是有值返回值,无值返回空字符串  

28.         JsonNode country_id = node.get("country_id");  

29.         System.out.println("country_id:"+country_id.asText() + " JsonNodeType:"+country_id.getNodeType());  

30.           

31.         JsonNode birthDate = node.get("birthDate");  

32.         System.out.println("birthDate:"+birthDate.asText()+" JsonNodeType:"+birthDate.getNodeType());  

33.           

34.         JsonNode nation = node.get("nation");  

35.         System.out.println("nation:"+ nation+ " JsonNodeType:"+nation.getNodeType());  

36.           

37.         JsonNode lakes = node.get("lakes");  

38.         System.out.println("lakes:"+lakes+" JsonNodeType:"+lakes.getNodeType());  

39.   

40.         JsonNode provinces = node.get("provinces");  

41.         System.out.println("provinces JsonNodeType:"+provinces.getNodeType());  

42.   

43.         boolean flag = true;  

44.         for (JsonNode provinceElements : provinces) {  

45.             //为了避免provinceElements多次打印,用flag控制打印,能体现provinceElements的JsonNodeType就可以了  

46.             if(flag){  

47.                 System.out.println("provinceElements JsonNodeType:"+provinceElements.getNodeType());  

48.                 System.out.println("provinceElements is container node? "+provinceElements.isContainerNode());  

49.                 flag = false;  

50.             }  

51.             Iterator<String> provinceElementFields = provinceElements.fieldNames();  

52.             while (provinceElementFields.hasNext()) {  

53.                 String fieldName = (String) provinceElementFields.next();  

54.                 String province;  

55.                 if ("population".equals(fieldName)) {  

56.                     province = fieldName + ":" + provinceElements.get(fieldName).asInt();  

57.                 }else{  

58.                     province = fieldName + ":" + provinceElements.get(fieldName).asText();  

59.                 }  

60.                 System.out.println(province);  

61.             }  

62.         }  

63.     }  

64. }  

程序运行后打印结果如下:

1. node JsonNodeType:OBJECT  

2. node is container Node ? true  

3. ---------得到所有node节点的子节点名称-------------------------  

4. country_id birthDate nation lakes provinces traffic   

5. -----------------------------------------------------  

6. country_id:China JsonNodeType:STRING  

7. birthDate:1949-10-01 JsonNodeType:STRING  

8. nation:["Han","Meng","Hui","WeiWuEr","Zang"] JsonNodeType:ARRAY  

9. lakes:["QingHai Lake","Poyang Lake","Dongting Lake","Taihu Lake"] JsonNodeType:ARRAY  

10. provinces JsonNodeType:ARRAY  

11. provinceElements JsonNodeType:OBJECT  

12. provinceElements is container node? true  

13. name:Shanxi  

14. population:37751200  

15. name:ZheJiang  

16. population:55080000  

 

在来看一下DeserializationExampleTreeModel2.java,本例中使用JsonNode.path的方法,path方法类似于DeserializationExampleTreeModel1.java中使用的get方法,

但当node不存在时,get方法返回null,而path返回MISSING类型的JsonNode

1. package com.jackson.json.treemodel;  

2.   

3. import java.io.File;  

4. import java.io.IOException;  

5. import java.util.Iterator;  

6.   

7. import com.fasterxml.jackson.core.JsonProcessingException;  

8. import com.fasterxml.jackson.databind.JsonNode;  

9. import com.fasterxml.jackson.databind.ObjectMapper;  

10.   

11. public class DeserializationExampleTreeModle2 {  

12.       

13.     public static void main(String[] args) throws JsonProcessingException, IOException{  

14.         ObjectMapper mapper = new ObjectMapper();  

15.         JsonNode node = mapper.readTree(new File("country2.json"));  

16.         //path方法获取JsonNode时,当对象不存在时,返回MISSING类型的JsonNode  

17.         JsonNode missingNode = node.path("test");  

18.         if(missingNode.isMissingNode()){  

19.             System.out.println("JsonNodeType : " + missingNode.getNodeType());  

20.         }  

21.   

22.         System.out.println("country_id:"+node.path("country_id").asText());  

23.           

24.         JsonNode provinces = node.path("provinces");  

25.         for (JsonNode provinceElements : provinces) {  

26.             Iterator<String> provincesFields = provinceElements.fieldNames();  

27.             while (provincesFields.hasNext()) {  

28.                 String fieldName = (String) provincesFields.next();  

29.                 String province;  

30.                 if("name".equals(fieldName)){  

31.                     province = fieldName +":"+ provinceElements.path(fieldName).asText();  

32.                 }else{  

33.                     province = fieldName +":"+ provinceElements.path(fieldName).asInt();  

34.                 }  

35.                 System.out.println(province);  

36.             }  

37.         }  

38.     }  

39.   

40. }  

程序运行打印结果:

1. JsonNodeType : MISSING  

2. country_id:China  

3. name:Shanxi  

4. population:37751200  

5. name:ZheJiang  

6. population:55080000  

3.Stream处理Json

(1)stream生成json

1. package com.jackson.json.streaming;  

2.   

3. import java.io.File;  

4. import java.io.FileWriter;  

5. import java.io.Exception;  

6.   

7. import com.fasterxml.jackson.core.JsonFactory;  

8. import com.fasterxml.jackson.core.JsonGenerator;  

9.   

10. public class StreamGeneratorJson {  

11.       

12.     public static void main(String[] args) throws Exception {  

13.         JsonFactory factory = new JsonFactory();  

14.         //从JsonFactory创建一个JsonGenerator生成器的实例  

15.         JsonGenerator generator = factory.createGenerator(new FileWriter(new File("country3.json")));  

16.           

17.         generator.writeStartObject();  

18.         generator.writeFieldName("country_id");  

19.         generator.writeString("China");  

20.         generator.writeFieldName("provinces");  

21.         generator.writeStartArray();  

22.         generator.writeStartObject();  

23.         generator.writeStringField("name", "Shanxi");  

24.         generator.writeNumberField("population", 33750000);  

25.         generator.writeEndObject();  

26.         generator.writeEndArray();  

27.         generator.writeEndObject();  

28.           

29.         generator.close();  

30.     }  

31.   

32. }  

程序运行后生成country3.json文件内容:

1. {"country_id":"China","provinces":[{"name":"Shanxi","population":33750000}]}  

 

(2)stream解析json:
现在adgcountry3.json,我们用Streaming API的方式来解析上面的Json,并查找json中population的值。

1. package com.jackson.json.streaming;  

2.   

3. import java.io.File;  

4. import java.io.IOException;  

5.   

6. import com.fasterxml.jackson.core.JsonFactory;  

7. import com.fasterxml.jackson.core.JsonParseException;  

8. import com.fasterxml.jackson.core.JsonParser;  

9. import com.fasterxml.jackson.core.JsonToken;  

10.   

11. /*Jackson API提供了token对每个Json对象,例如,Json开始符号“{”是token指向的第一个解析的对象, 

12.  key:value键值对是另一个单独的对象。这个API很强大,但也需要编写大量代码。不推荐使用,平时更多的是使用DataBinding和TreeModel来处理json 

13.  */  

14. public class StreamParserJson {  

15.     public static void main(String[] args) throws JsonParseException,  

16.             IOException {  

17.         JsonFactory factory = new JsonFactory();  

18.         // 从JsonFactory创建JsonParser解析器的实例  

19.         JsonParser parser = factory.createParser(new File("country3.json"));  

20.   

21.         while (!parser.isClosed()) {  

22.             // 得到一个token,第一次遍历时,token指向json文件中第一个符号"{"  

23.             JsonToken token = parser.nextToken();  

24.             if (token == null) {  

25.                 break;  

26.             }  

27.             // 我们只查找 country3.json中的"population"字段的值,能体现解析的流程就可以了  

28.             // 当key是provinces时,我们进入provinces,查找population  

29.             if (JsonToken.FIELD_NAME.equals(token)  

30.                     && "provinces".equals(parser.getCurrentName())) {  

31.                 token = parser.nextToken();  

32.                 if (!JsonToken.START_ARRAY.equals(token)) {  

33.                     break;  

34.                 }  

35.                 // 此时,token指向的应该是"{"  

36.                 token = parser.nextToken();  

37.                 if (!JsonToken.START_OBJECT.equals(token)) {  

38.                     break;  

39.                 }  

40.                 while (true) {  

41.                     token = parser.nextToken();  

42.                     if (token == null) {  

43.                         break;  

44.                     }  

45.                     if (JsonToken.FIELD_NAME.equals(token)  

46.                             && "population".equals(parser.getCurrentName())) {  

47.                         token = parser.nextToken();  

48.                         System.out.println(parser.getCurrentName() + " : "  

49.                                 + parser.getIntValue());  

50.                     }  

51.                 }  

52.             }  

53.         }  

54.     }  

55.   

56. }  

程序运行后,在控制台打印结果如下:

1. population : 33750000  

 

总结

上面的例子中,分别用3种方式处理Json,我的体会大致如下:

 

Stream API方式是开销最低、效率最高,但编写代码复杂度也最高,在生成Json时,需要逐步编写符号和字段拼接json,在解析Json时,需要根据token指向也查找json值,生成和解析json都不是很方便,代码可读性也很低。

Databinding处理Json是最常用的json处理方式,生成json时,创建相关的java对象,并根据json内容结构把java对象组装起来,最后调用writeValue方法即可生成json,

解析时,就更简单了,直接把json映射到相关的java对象,然后就可以遍历java对象来获取值了。

TreeModel处理Json,是以树型结构来生成和解析json,生成json时,根据json内容结构,我们创建不同类型的节点对象,组装这些节点生成json。解析json时,它不需要绑定json到java bean,根据json结构,使用path或get方法轻松查找内容。

 

学习参考:http://www.cnblogs.com/lee0oo0/articles/2652528.htm

Example

下面的例子是基于Jackson 2.x版本的树模型的Json解析。

要解析的Json字符串:

1. String data = {  

2.             "type":2,"range":1,"start":1368417600,"end":1368547140,"cityName":"天津",  

3.             "companyIds":["12000001"],  

4.             "companyNames":["天津"],  

5.             "12000001":{  

6.                 "data":[47947,48328,48573,48520],  

7.                 "timestamps":[1368417600,1368417900,1368418200,1368418500]  

8.             }  

9.     }  

示例代码:

1. package com.cennavi.dqe.test;  

2.   

3. import java.io.IOException;  

4. import java.text.SimpleDateFormat;  

5. import java.util.Date;  

6. import java.util.TimeZone;  

7.   

8. import com.fasterxml.jackson.core.JsonProcessingException;  

9. import com.fasterxml.jackson.databind.JsonNode;  

10. import com.fasterxml.jackson.databind.ObjectMapper;  

11.   

12. public class ParseJsonTest {  

13.   

14.     /** 

15.      * @param args 

16.      */  

17.     public static void main(String[] args) {  

18.         String data = "{\"type\":2,\"range\":1,\"start\":1368417600,\"end\":1368547140,"  

19.                 + "\"cityName\":\"天津\",\"companyIds\":[\"12000001\"],\"companyNames\":[\"天津\"],"  

20.                 + "\"12000001\":{\"data\":[47947,48328,48573,48520],"  

21.                 + "\"timestamps\":[1368417600,1368417900,1368418200,1368418500]}}";  

22.         String data2 = parseJson(data);  

23.         System.out.println(data2);  

24.     }  

25.   

26.     public static String parseJson(String data) {  

27.         // 用来展现解析Json得到的值  

28.         StringBuffer buf = new StringBuffer();  

29.         try {  

30.             ObjectMapper mapper = new ObjectMapper();  

31.             JsonNode rootNode = mapper.readTree(data); // 读取Json  

32.             // rootNode.path("xx")返回的还是一个JsonNode对象,调用该JsonNode的相应方法,得到键对应的值  

33.             int type = rootNode.path("type").asInt();  

34.             int range = rootNode.path("range").asInt();  

35.             long start = rootNode.path("start").asLong();  

36.             long end = rootNode.path("end").asLong();  

37.             String cityName = rootNode.path("cityName").asText();  

38.   

39.             // 转换时间格式  

40.             SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmm");  

41.             sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));  

42.   

43.             String str = "类型(type):" + type + "\r\n" + "范围(range):" + range  

44.                     + "\r\n" + "开始时间(start):"  

45.                     + sdf.format(new Date(start * 1000)) + "\r\n"  

46.                     + "结束时间(end):" + sdf.format(new Date(end * 1000)) + "\r\n"  

47.                     + "城市名称(cityName):" + cityName;  

48.             buf.append(str);  

49.             // 得到companyIds的JsonNode对象  

50.             JsonNode companyIds = rootNode.path("companyIds");  

51.             JsonNode companyNames = rootNode.path("companyNames");  

52.   

53.             // 遍历companyIds中的内容  

54.             for (int i = 0; i < companyIds.size(); i++) {  

55.                 String companyId = companyIds.get(i).asText();  

56.                 // 本例解析的Json字符串中companyIds与companyNames的长度是相同的,所有直接遍历companyNames  

57.                 String companyName = companyNames.get(i).asText();  

58.                 // companyId的值:12000001,对应Json串中的  

59.                 // "12000001":{"data":[...],"timestamps":[....]}  

60.                 JsonNode infoNode = rootNode.path(companyId);  

61.                 // 得到"12000001":{"data":[...],"timestamps":[....]}中的data和timestamps的JsonNode对象  

62.                 JsonNode dataNode = infoNode.path("data");  

63.                 JsonNode timestampsNode = infoNode.path("timestamps");  

64.                 // 遍历data和timestamps 本例中data.size与timestamps.size是相等的  

65.   

66.                 buf.append("\r\n{\r\n  公司ID(companyId):" + companyId  

67.                         + "\r\n  公司名称(companyName):" + companyName + "\r\n"  

68.                         + " data:");  

69.                 for (int j = 0; j < dataNode.size(); j++) {  

70.                     long dataValue = dataNode.get(j).asLong();  

71.                     buf.append(dataValue + ",");  

72.                 }  

73.                 buf.append("\r\n time:");  

74.                 for (int k = 0; k < timestampsNode.size(); k++) {  

75.                     long timeValue = timestampsNode.get(k).asLong();  

76.                     buf.append(sdf.format(new Date(timeValue * 1000)) + ",");  

77.                 }  

78.                 buf.append("\r\n}\r\n");  

79.             }  

80.         } catch (JsonProcessingException e) {  

81.             e.printStackTrace();  

82.         } catch (IOException e) {  

83.             // TODO 自动生成的 catch 块  

84.             e.printStackTrace();  

85.         }  

86.         return buf.toString();  

87.     }  

88.   

89. }  

测试结果:

1. 类型(type):2  

2. 范围(range):1  

3. 开始时间(start):201305131200  

4. 结束时间(end):201305142359  

5. 城市名称(cityName):天津  

6. {  

7.   公司ID(companyId):12000001  

8.   公司名称(companyName):天津  

9.   data:47947,48328,48573,48520,  

10.   time:201305131200,201305131205,201305131210,201305131215  

11. }  

Jackson - Annotations

想要了解更多内容,请查看annotations列表。下面只列出一些常用的Json注解。

@JsonProperty

它关联json字段到Java属性。可以标记属性,也可以用来标记属性的getter/setter方法。当标记属性时,可以对属性字段重命名。当标记方法时,可以把json字段关联到java属性的getter或setter方法。

@JsonCreator

json反序列化为java对象时,该注解用于定义构造函数。当从json创建java时,@JsonCreator注解的构造函数被会调用,如果没有@JsonCreator注解,则默认调用java类的无参构造函数,此时,如果java类中只有有参构造函数,而无默认的无参构造函数,在反序列化时会抛出这样的异常:com.fasterxml.jackson.databind.JsonMappingException,所以,当我们不使用@JsonCreator指定反序列化的构造函数,而又在java类中重载了构造函数时,一定要记得编写类的无参构造函数。

@JsonAnyGetter@JsonAnySetter

用于标记类方法,设置和读取json字段作为键值对存储到map中,这两个注解标记的方法不会处理任何java类中已经定义过的属性变量,只对java中未定义的json字段作处理。

@JsonIgnoreProperties@JsonIgnore

用于标记属性,在json与java之间相互转化时,将忽略被此注解标记的属性。@JsonIgnoreProperties是类级别注解,可以忽略多个属性,@JsonIgnore用来标注单个属性。

@JsonTypeInfo@JsonSubTypes

用于维持java类的子类信息,将子类对象类型信息嵌入到json中,以便反序列化创建具体的对象。

 

Example

下面通过例子来演示注解的使用

example.1

读取company.json,反序列化json,创建java对象,并遍历信息

company.json

1. {  

2.   "name" : "Oracle",  

3.   "HQ" : "California",  

4.   "birthDate" : "1977-01-01",  

5.   "departments" : [ {  

6.     "name" : "development",  

7.     "employee_number" : 5000,  

8.     "projectManager" : "jack",  

9.     "product" : "oracle_db"  

10.   }, {  

11.     "name" : "test",  

12.     "employee_number" : 500,  

13.     "projectManager" : "rose",  

14.     "product" : "oracle_test"  

15.   } ]  

16. }  

Company.java

1. package com.jackson.json.annotation;  

2.   

3. import java.util.Date;  

4.   

5. import com.fasterxml.jackson.annotation.JsonCreator;  

6. import com.fasterxml.jackson.annotation.JsonIgnore;  

7. import com.fasterxml.jackson.annotation.JsonProperty;  

8.   

9. public class Company {  

10.     private String name;  

11.     @JsonProperty("HQ")   //java属性headquarters序列化到json字段的名称为HQ  

12.     private String headquarters;  

13.     private Department[] departments;  

14.     @JsonIgnore         //在序列化与反序列化时,忽略birthDate属性  

15.     private Date birthDate;  

16.   

17.     public Date getBirthDate() {  

18.         return birthDate;  

19.     }  

20.   

21.     @JsonCreator  

22.     public Company(@JsonProperty("name") String name) {  

23.         this.name = name;  

24.     }  

25.   

26.     public String getName() {  

27.         return name;  

28.     }  

29.   

30.     public String getHeadquarters() {  

31.         return headquarters;  

32.     }  

33.   

34.     public Department[] getDepartments() {  

35.         return departments;  

36.     }  

37.   

38.     public void setDepartments(Department[] departments) {  

39.         this.departments = departments;  

40.     }  

41.   

42. }  

Department.java

1. package com.jackson.json.annotation;  

2.   

3. import java.util.HashMap;  

4. import java.util.Map;  

5.   

6. import com.fasterxml.jackson.annotation.JsonAnyGetter;  

7. import com.fasterxml.jackson.annotation.JsonAnySetter;  

8. import com.fasterxml.jackson.annotation.JsonCreator;  

9. import com.fasterxml.jackson.annotation.JsonProperty;  

10.   

11. public class Department {  

12.     private String name;  

13.     private String pm;  

14.     private Map<String, Object> otherProperties = new HashMap<String, Object>(); //otherProperties用来存放Department中未定义的json字段  

15.       

16.     @JsonCreator   //指定json反序列化创建Department对象时调用此构造函数  

17.     public Department(@JsonProperty("name") String name){  

18.         this.name = name;  

19.     }  

20.       

21.     @JsonProperty("projectManager")  //将company.json中projectManager字段关联到getPm方法  

22.     public String getPm() {  

23.         return pm;  

24.     }  

25.   

26.     public String getName() {  

27.         return name;  

28.     }  

29.   

30.     public Object get(String key) {  

31.         return otherProperties.get(key);  

32.     }  

33.   

34.     @JsonAnyGetter    //得到所有Department中未定义的json字段的  

35.     public Map<String, Object> any() {  

36.         return otherProperties;  

37.     }  

38.   

39.     @JsonAnySetter  

40.     public void set(String key, Object value) {  

41.         otherProperties.put(key, value);  

42.     }  

43.   

44. }  


DeserializationExample.java

1. package com.jackson.json.annotation;  

2.   

3. import java.io.File;  

4.   

5. import com.fasterxml.jackson.databind.DeserializationFeature;  

6. import com.fasterxml.jackson.databind.ObjectMapper;  

7.   

8. public class DeserializationExample {  

9.     public static void main(String[] args) throws Exception {  

10.         ObjectMapper mapper = new ObjectMapper();  

11.         mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); //禁止未知属性打断反序列化  

12.           

13.         Company company = mapper.readValue(new File("company_back.json"), Company.class);  

14.         System.out.print("company_name:"+company.getName()+"\t");  

15.         System.out.print("headquarters:"+company.getHeadquarters()+"\t");  

16.         System.out.println("birthDate:"+company.getBirthDate()); //birthDate被标记为@JsonIgnore,所以此处得到的值应该为null  

17.           

18.         Department[] departments = company.getDepartments();  

19.           

20.         for (Department department : departments) {  

21.             System.out.print("department_name:" + department.getName()+"\t");  

22.             System.out.print("employee_number:" + department.getPm()+"\t");  

23.             //Department中未定义的字段product,employee_number  

24.             System.out.print("product:"+department.get("product")+"\t");   

25.             System.out.println("projectManager:"+department.get("employee_number"));  

26.         }  

27.     }  

28.   

29. }  


程序运行控制台打印结果如下:

1. company_name:Oracle headquarters:California birthDate:null  

2. department_name:development employee_number:jack    product:oracle_db   projectManager:5000  

3. department_name:test    employee_number:rose    product:oracle_test projectManager:500  


example.2

下面例子演示,当java对象中包含List<Object>属性时,如何序列化与反序列化。

当java对象中含List<Object>时,如果Object一个抽象类或接口,这里就会出现java多态的现象,比如,List<Animal>,Animal是个抽象类,并且有多个子类时,由于List中保存的Animal没有明确指向具体的子类或实现类,json反序列化java对象时就会抛出提示:Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException:Can not construct instance of Animal, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information

@JsonTypeInfo与@JsonSubTypes就是解决此类问题,通过注解,可以在序列化时,保存具体的类型信息到json中,当json反序列到java对象时,就可以根据具体类型信息创建正确的java对象。

Zoo.java

1. package com.jackson.json.databinding.list;  

2.   

3. import java.util.List;  

4.   

5. import com.fasterxml.jackson.annotation.JsonCreator;  

6. import com.fasterxml.jackson.annotation.JsonProperty;  

7.   

8. public class Zoo {  

9.     public String name;  

10.     public String city;  

11.     public List<Animal> animals;  

12.       

13.     @JsonCreator  

14.     public Zoo(@JsonProperty("name") String name, @JsonProperty("city") String city) {  

15.         this.name = name;  

16.         this.city = city;  

17.     }  

18.       

19.     public void setAnimals(List<Animal> animals) {  

20.         this.animals = animals;  

21.     }  

22.   

23.     @Override  

24.     public String toString() {  

25.         return "Zoo [name=" + name + ", city=" + city + ", animals=" + animals  

26.                 + "]";  

27.     }  

28.       

29. }  

Animal.java

1. package com.jackson.json.databinding.list;  

2.   

3. import com.fasterxml.jackson.annotation.JsonSubTypes;  

4. import com.fasterxml.jackson.annotation.JsonSubTypes.Type;  

5. import com.fasterxml.jackson.annotation.JsonTypeInfo;  

6. import com.fasterxml.jackson.annotation.JsonTypeInfo.As;  

7. import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;  

8.   

9. @JsonTypeInfo(use=Id.CLASS,include=As.PROPERTY,property="@class")  

10. @JsonSubTypes({@Type(value=Lion.class,name="lion"),@Type(value=Elephant.class,name="elephant")})  

11. public abstract class Animal {  

12.     String name;  

13.     String type;  

14. }  

Lion.java

1. package com.jackson.json.databinding.list;  

2.   

3. import com.fasterxml.jackson.annotation.JsonCreator;  

4. import com.fasterxml.jackson.annotation.JsonProperty;  

5.   

6. public class Lion extends Animal {  

7.       

8.     private String name;  

9.       

10.     @JsonCreator  

11.     public Lion(@JsonProperty("name") String name) {  

12.         this.name = name;  

13.     }  

14.   

15.     public String getName() {  

16.         return name;  

17.     }  

18.       

19.     public String getType() {  

20.         return "carnivorous";  

21.     }  

22.   

23.     @Override  

24.     public String toString() {  

25.         return "Lion [name=" + name + ", getName()=" + getName()  

26.                 + ", getType()=" + getType() + "]";  

27.     }  

28.       

29. }  

Elephant.java

1. package com.jackson.json.databinding.list;  

2.   

3. import com.fasterxml.jackson.annotation.JsonCreator;  

4. import com.fasterxml.jackson.annotation.JsonProperty;  

5.   

6. public class Elephant extends Animal {  

7.     private String name;  

8.   

9.     @JsonCreator  

10.     public Elephant(@JsonProperty("name") String name) {  

11.         this.name = name;  

12.     }  

13.       

14.     public String getName() {  

15.         return name;  

16.     }  

17.       

18.     public String getType() {  

19.         return "herbivorous";  

20.     }  

21.   

22.     @Override  

23.     public String toString() {  

24.         return "Elephant [getName()=" + getName() + ", getType()=" + getType()  

25.                 + "]";  

26.     }  

27.       

28. }  


SerializeExmaple.java

1. package com.jackson.json.databinding.list;  

2.   

3. import java.io.File;  

4. import java.io.IOException;  

5. import java.util.ArrayList;  

6. import java.util.List;  

7.   

8. import com.fasterxml.jackson.databind.ObjectMapper;  

9. import com.fasterxml.jackson.databind.SerializationFeature;  

10.   

11. public class SerializeExample {  

12.     public static void main(String[] args) throws Exception {  

13.         Zoo zoo = new Zoo("SH Wild Park", "ShangHai");  

14.         Lion lion = new Lion("Samba");  

15.         Elephant elephant = new Elephant("Manny");  

16.         List<Animal> animals = new ArrayList<Animal>();  

17.         animals.add(lion);  

18.         animals.add(elephant);  

19.         zoo.setAnimals(animals);  

20.           

21.         ObjectMapper mapper = new ObjectMapper();  

22.         mapper.configure(SerializationFeature.INDENT_OUTPUT, true);  

23.         mapper.writeValue(new File("zoo.json"), zoo);  

24.     }  

25.   

26. }  

生成zoo.json内容如下:

1. {  

2.   "name" : "SH Wild Park",  

3.   "city" : "ShangHai",  

4.   "animals" : [ {  

5.     "@class" : "com.jackson.json.databinding.list.Lion",  

6.     "name" : "Samba",  

7.     "type" : "carnivorous"  

8.   }, {  

9.     "@class" : "com.jackson.json.databinding.list.Elephant",  

10.     "name" : "Manny",  

11.     "type" : "herbivorous"  

12.   } ]  

13. }  


反序列化,DeserializeExmaple.java

1. package com.jackson.json.databinding.list;  

2.   

3. import java.io.File;  

4.   

5. import com.fasterxml.jackson.databind.ObjectMapper;  

6.   

7. public class DeserializeExample {  

8.   

9.     public static void main(String[] args) throws Exception {  

10.         ObjectMapper mapper = new ObjectMapper();  

11.         Zoo zoo = mapper.readValue(new File("zoo.json"), Zoo.class);  

12.         System.out.println(zoo);  

13.     }  

14. }  


这里对反序列化后的Zoo对象不作详细遍历了,只打印toString看一下,结果如下,正确创建了Lion和Elephant对象

1. Zoo [name=SH Wild Park, city=ShangHai, animals=[Lion [name=Samba, getName()=Samba, getType()=carnivorous], Elephant [getName()=Manny, getType()=herbivorous]]]  

 

我们还可以用另一个种方法来替代JsonSubTypes注释,现在,我们对Animal.java类稍作修改,隐去@JsonSubTypes注解,保留@JsonInfoType注解.这一次,我们直接序列化List<Animal>

SerializeExample2.java

1. package com.jackson.json.databinding.list;  

2.   

3. import java.io.File;  

4. import java.io.IOException;  

5. import java.util.ArrayList;  

6. import java.util.List;  

7.   

8. import com.fasterxml.jackson.core.type.TypeReference;  

9. import com.fasterxml.jackson.databind.ObjectMapper;  

10. import com.fasterxml.jackson.databind.SerializationFeature;  

11.   

12. public class SerializeExample {  

13.     public static void main(String[] args) throws Exception {  

14.         Zoo zoo = new Zoo("SH Wild Park", "ShangHai");  

15.         Lion lion = new Lion("Samba");  

16.         Elephant elephant = new Elephant("Manny");  

17.         List<Animal> animals = new ArrayList<Animal>();  

18.         animals.add(lion);  

19.         animals.add(elephant);  

20.         zoo.setAnimals(animals);  

21.           

22.         ObjectMapper mapper = new ObjectMapper();  

23.         mapper.configure(SerializationFeature.INDENT_OUTPUT, true);  

24.         mapper.writerFor(new TypeReference<List<Animal>>() {  

25.         }).writeValue(new File("animal.json"), animals);  

26.           

27.     }  

28.   

29. }  

生成 animal.json,内容如下:

1. [ {  

2.   "@class" : "com.jackson.json.databinding.list.Lion",  

3.   "name" : "Samba",  

4.   "type" : "carnivorous"  

5. }, {  

6.   "@class" : "com.jackson.json.databinding.list.Elephant",  

7.   "name" : "Manny",  

8.   "type" : "herbivorous"  

9. } ]  

 

总结

当采用数据绑定(DataBinding)方式处理json时,适当的使用Jackson Annotations可以帮助我们更好的解决问题,特别体现在序列化List时,解决多态的问题,以保证反序化到java对象时的正确性。@JsonAnyGetter,@JsonAnySetter,@JsonProperty都是很常用的注解,可以帮助我们更简洁的处理java对象与json之间的相互转化。

 

© 著作权归作者所有

共有 人打赏支持
侠客人生
粉丝 15
博文 43
码字总数 82954
作品 0
朝阳
fastjson1.2.8原理

fastjson是阿里巴巴的项目,用于进行java对象与JSON字符串之间的序列化(对象转JSON)和反序列化(JSON转对象)。 所以fastjson分为序列化和反序列化两大核心功能,所有API都几种在JSON类中(...

拉风小野驴
2016/03/11
102
0
python --- json模块和pickle模块详解

  json:JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式(用于数据序列化和反序列化)。(适用于多种编程语言,可以与其他编程语言做数据交换)   pickle:...

码农47
2017/08/19
0
0
Java序列化与JSON序列化大比拼

一、背景 有项目需要传输Map结构的数据,有人倾向用Java序列化来做,有人倾向用JSON的序列化来做。所以我们还是比比吧。 Java观点:Object2Object,使用时简单快速。 JSON观点:JSON格式与语...

NoahX
2013/03/10
0
20
PHP多种序列化以及反序列化

PHP多种序列化以及反序列化 PHP点点通2016-09-2147 阅读 序列化PHP 序列化是将变量转换为可保存或传输的字符串的过程;反序列化就是在适当的时候把这个字符串再转化成原来的变量使用。这两个...

PHP点点通
2016/09/21
0
0
jackson常用注解和spring中的配置

spring默认使用的是jackson处理json的序列化和反序列化,有一些细节和小坑,基于spring4和jackson2.8做一些说明 @JsonIgnore @JsonIgnore是jackson的注解,jackson1版本和2版本没有区别,通常...

肥肥小浣熊
2017/12/01
0
0

没有更多内容

加载失败,请刷新页面

加载更多

DES/3DES(TripleDES)加密、解密测试数据

以下结果经 PHP+openssl及VB.NET验证,ECB模式。 PHP 7.0.10 (cli) (built: Aug 18 2016 09:48:53) ( ZTS ) OpenSSL Library Version: OpenSSL 1.0.1t 3 May 2016 VB.net 2003 ****** DES(S......

SamXIAO
23分钟前
0
0
Java11的新特性

Java语言特性系列 Java5的新特性 Java6的新特性 Java7的新特性 Java8的新特性 Java9的新特性 Java10的新特性 Java11的新特性 Java12的新特性 序 本文主要讲述一下Java11的新特性 版本号 java...

go4it
24分钟前
1
0
Maven常用命令及相关笔记

Maven常用命令 dos指令 4. 编译源代码: mvn compile 6. 运行测试: mvn test 8. 打包: mvn package 9. 在本地Repository中安装jar: mvn install 10. 清除产生的项目: mvn clean 4. 运行项...

颖伙虫
30分钟前
0
0
swagger2.2.2 与 spring cloud feign冲突 导致服务请求报空

swagger2.2.2 与 spring cloud feign冲突 Java代码 Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.choosefine.web.console.ar......

泉天下
33分钟前
0
0
设计模式之 明确责任 观察者模式 状态模式 责任链模式

观察者模式是任务分发的一种模式。 如果认为我们设计的系统的各个模块(或子系统)的最终目的是完成共同任务,那么这个任务如何分配到多个模块的就是我们遇到的第一个问题。简单设计场合我们...

backbye
38分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部