概述
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之间的相互转化。