Java解析json(二):jackson
来源:互联网 发布:广电网络面临的形势 编辑:程序博客网 时间:2024/06/10 16:58
官方参考
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
简介
Jackson框架是基于Java平台的一套数据处理工具,被称为“最好的Java Json解析器”。
Jackson有两个主要分支,1.x处于维护状态,只会发布bug修复版本。2.x还在积极地开发当中。这两个版本的Java包名和Maven artifact不一样,所以它们不互相兼容,但是可以和平共存,也就是项目可以同时依赖1.x和2.x而不会发生冲突。
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开头。
本文以2.x为主…
主要模块
1. 核心模块
核心模块是扩展模块构建的基础,到2.7版本为止,共有3个核心模块(依赖关系从上到下): ***Streaming*** : jackson-core jar,定义了底层的streaming API和实现了Json特性。 ***Annotations*** : jackson-annotations jar,包含了标准的Jackson注解。 ***Databind*** : jackson-databind jar,实现了数据绑定和对象序列化,它依赖于streaming和annotations的包。
2. 第三方数据类型模块
这些扩展是插件式的Jackson模块,用ObjectMapper.registerModule()注册,并且通过添加serializers和deserializers以便Databind包(ObjectMapper / ObjectReader / ObjectWriter)可以读写这些类型,来增加对各种常用的Java库的数据类型的支持。参考https://github.com/FasterXML/jacksonThird-party datatype modules。
3. 数据格式模块
Jackson也有处理程序对JAX-RS标准实现者例如Jersey, RESTeasy, CXF等提供了数据格式支持。处理程序实现了MessageBodyReader和MessageBodyWriter,目前支持的数据格式包括JSON, Smile, XML, YAML和CBOR。
数据格式提供了除了Json之外的数据格式支持,它们绝大部分仅仅实现了streaming API abstractions,以便数据绑定组件可以按照原来的方式使用。另一些(几乎不需要)提供了databind标准功能来处理例如schemas。参考https://github.com/FasterXML/jacksonData format modules
准备工作
JDK1.7,依赖jackon的三个核心类库:
- jackson-core-2.5.3.jar
- jackson-annotations-2.5.3.jar
- jackson-databind-2.5.3.jar
maven依赖:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.7.4</version></dependency><dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.7.4</version></dependency><dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.7.4</version></dependency>
处理Json
Jackson提供了三种可选的Json处理方法:流式API(Streaming API) 、树模型(Tree Model)、数据绑定(Data Binding)。三种处理Json的方式的特性:
- Streaming API:是效率最高的处理方式(开销低、读写速度快,但程序编写复杂度高)
- Tree Model:是最灵活的处理方式
- Data Binding:是最常用的处理方式
1.Data Binding
主要使用ObjectMapper来操作Json,默认情况下会使用BeanSerializer来序列化POJO。
如果是解析,那么如下的例子里的TestJson必须要有setters,且setters必须是public修饰的,否则属性的值将会为null。
如果是生成,那么必须有getters,且getters必须是public修饰的。
如果属性不是private修饰,那么可以不用有getters和setters。(参考访问修饰符)
要点:
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(jsonFile, Bean);
mapper.readValue(jsonFile, Bean.class/Collection< Bean >);
(1)生成json
city.java
package com.myjackson.databinding;//市public class City { private Integer id; private String cityName; public City(){} public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getCityName() { return cityName; } public void setCityName(String cityName) { this.cityName = cityName; }}
province.java
package com.myjackson.databinding;import java.util.Date;import java.util.List;//省public class Province { private Integer id; private String name; private Date birthDate; private List<City> cities; public Province(){} public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<City> getCities() { return cities; } public void setCities(List<City> cities) { this.cities = cities; } public Date getBirthDate() { return birthDate; } public void setBirthDate(Date birthDate) { this.birthDate = birthDate; }}
counry.java
package com.myjackson.databinding;import java.util.Date;import java.util.HashMap;import java.util.List;import java.util.Map;//国家public class Country { private Integer id; private String countryName; private Date establishTime; private List<Province> provinces; private String[] lakes; private Map<String, String> forest = new HashMap<String, String>(); public Country(){ } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getCountryName() { return countryName; } public void setCountryName(String countryName) { this.countryName = countryName; } public Date getEstablishTime() { return establishTime; } public void setEstablishTime(Date establishTime) { this.establishTime = establishTime; } public List<Province> getProvinces() { return provinces; } public void setProvinces(List<Province> provinces) { this.provinces = provinces; } public String[] getLakes() { return lakes; } public void setLakes(String[] lakes) { this.lakes = lakes; } public Map<String, String> getForest() { return forest; } public void setForest(Map<String, String> forest) { this.forest = forest; } }
测试案例
@Test public void Bean2JsonStr() throws ParseException, JsonGenerationException, JsonMappingException, IOException{ // 使用ObjectMapper转化对象为Json ObjectMapper mapper = new ObjectMapper(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); mapper.setDateFormat(dateFormat); //设置日期序列化格式 City city1 = new City(); city1.setId(1); city1.setCityName("gz"); City city2 = new City(); city2.setId(2); city2.setCityName("dg"); Province province = new Province(); province.setId(1); province.setName("GD"); province.setBirthDate(new Date()); List<City> cities = new ArrayList<City>(); cities.add(city1); cities.add(city2); province.setCities(cities); Country country = new Country(); country.setCountryName("China"); country.setId(1); country.setEstablishTime(dateFormat.parse("1949-10-01")); country.setLakes(new String[] { "Qinghai Lake", "Poyang Lake","Dongting Lake", "Taihu Lake" }); HashMap<String, String> forest = new HashMap<String, String>(); forest.put("no.1", "dxal"); forest.put("no.2", "xxal"); country.setForest(forest); List<Province> provinces = new ArrayList<Province>(); provinces.add(province); country.setProvinces(provinces); mapper.configure(SerializationFeature.INDENT_OUTPUT, true); // 为了使JSON视觉上的可读性,在生产中不需如此,会增大Json的内容 mapper.setSerializationInclusion(Include.NON_EMPTY); // 配置mapper忽略空属性 mapper.writeValue(new File("country.json"), country); // 默认情况,Jackson使用Java属性字段名称作为 Json的属性名称,也可以使用Jackson annotations(注解)改变Json属性名称 }
运行得到country.json:
{ "id" : 1, "countryName" : "China", "establishTime" : "1949-10-01", "provinces" : [ { "id" : 1, "name" : "GD", "birthDate" : "2017-02-04", "cities" : [ { "id" : 1, "cityName" : "gz" }, { "id" : 2, "cityName" : "dg" } ] } ], "lakes" : [ "Qinghai Lake", "Poyang Lake", "Dongting Lake", "Taihu Lake" ], "forest" : { "no.1" : "dxal", "no.2" : "xxal" }}
(2)解析json
@Test public void JsonStr2Bean() throws JsonParseException, JsonMappingException, IOException{ ObjectMapper mapper = new ObjectMapper(); File jsonFile = new File("country.json"); //当反序列化json时,未知属性会引起的反序列化被打断,这里我们禁用未知属性打断反序列化功能, //因为,例如json里有10个属性,而我们的bean中只定义了2个属性,其它8个属性将被忽略 mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); Country country = mapper.readValue(jsonFile, Country.class); System.out.println(country.getCountryName()+country.getEstablishTime()); List<Province> provinces = country.getProvinces(); for (Province province : provinces) { System.out.println("province:"+province.getName() + "\n" + "birthDate:"+province.getBirthDate()); for (City city: province.getCities()) { System.out.println(city.getId()+" "+city.getCityName()); } } }
输出结果:
ChinaSat Oct 01 08:00:00 CST 1949province:GDgetBirthDate:Sat Feb 04 08:00:00 CST 20171 gz2 dg
解析的时候如果碰到集合类,那么可以使用TypeReference类
@Test public void JsonStr2List() throws IOException{ City city1 = new City(); city1.setId(1); city1.setCityName("gz"); City city2 = new City(); city2.setId(2); city2.setCityName("dg"); List<City> cities = new ArrayList<City>(); cities.add(city1); cities.add(city2); ObjectMapper mapper = new ObjectMapper(); String listJsonStr = mapper.writeValueAsString(cities); System.out.println(listJsonStr); List<City> list = mapper.readValue(listJsonStr, new TypeReference<List<City>>(){} ); for (City city: list) { System.out.println("id:"+city.getId()+" cityName:"+city.getCityName()); } }
2.Streaming API
Jackson提供了一套底层API来解析Json字符串,这个API为每个Json对象提供了符号。例如, ‘{’ 是解析器提供的第一个对象(writeStartObject()),键值对是解析器提供的另一个单独对象(writeString(key,value))。这些API很强大,但是需要大量的代码。大多数情况下,Tree Model和Data Binding可以代替Streaming API。
上面代码如果注释掉 city1.setId(1);这行,结果为:
[{"id":null,"cityName":"gz"},{"id":2,"cityName":"dg"}]id:null cityName:gzid:2 cityName:dg
但假如想让id为null的不输出,不为null的输出除了 mapper.setSerializationInclusion(Include.NON_EMPTY); // 配置mapper忽略空属性
这种方法外还可以在ObjectMapper中注册一个自定义的序列化JsonSerializer和反序列化
JsonDeSerializer:
CityJsonSerializer.java
package com.myjackson.databinding;import java.io.IOException;import com.fasterxml.jackson.core.JsonGenerator;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.JsonSerializer;import com.fasterxml.jackson.databind.SerializerProvider;public class CityJsonSerializer extends JsonSerializer<City>{ @Override public void serialize(City city, JsonGenerator jsonGenerator, SerializerProvider arg2) throws IOException, JsonProcessingException { jsonGenerator.writeStartObject(); if ( city.getId()!=null) { jsonGenerator.writeNumberField("id", city.getId()); } jsonGenerator.writeStringField("cityName", city.getCityName()); jsonGenerator.writeEndObject(); }}
CityJsonDeSerializer.java
package com.myjackson.databinding;import java.io.IOException;import java.util.ArrayList;import java.util.List;import com.fasterxml.jackson.core.JsonParser;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.core.JsonToken;import com.fasterxml.jackson.databind.DeserializationContext;import com.fasterxml.jackson.databind.JsonDeserializer;public class CityJsonDeSerializer extends JsonDeserializer<List<City>>{ @Override public List<City> deserialize(JsonParser parser,DeserializationContext deserializationcontext) throws IOException, JsonProcessingException { List<City> list = new ArrayList<City>(); // 开始解析数组,第一个JsonToken必须是JsonToken.START_ARRAY"[" if (!JsonToken.START_ARRAY.equals(parser.getCurrentToken())) { System.out.println(parser.getCurrentToken()); return null; } // 解析符号直到字符串结尾 while (!parser.isClosed()) { // 如果有必要的话,这个方法会沿着流前进直到足以确下一个JsonToken的类型 JsonToken token = parser.nextToken(); // 如果是最后一个JsonToken,那么就结束了 if (token == null) break; // 数组的每个元素都是对象,因此下一个JsonToken是JsonToken.START_OBJECT"{" if (!JsonToken.START_OBJECT.equals(token)) { break; } City city = null; // 输出id字段的值 while (true) { if (JsonToken.START_OBJECT.equals(token)) { city = new City(); } token = parser.nextToken(); if (token == null) break; if (JsonToken.FIELD_NAME.equals(token) ) { if("id".equals(parser.getCurrentName())){ token = parser.nextToken(); city.setId(parser.getIntValue()); }else if("cityName".equals(parser.getCurrentName())){ token = parser.nextToken(); city.setCityName(parser.getText()); } } if(JsonToken.END_OBJECT.equals(token)){ list.add(city); } } } return list; }}
测试:
@Test public void StreamJsonStr2List() throws IOException{ City city1 = new City(); //city1.setId(1); city1.setCityName("gz"); City city2 = new City(); city2.setId(2); city2.setCityName("dg"); List<City> cities = new ArrayList<City>(); cities.add(city1); cities.add(city2); ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(City.class, new CityJsonSerializer()); mapper.registerModule(module); String listJsonStr = mapper.writeValueAsString(cities); System.out.println(listJsonStr); ObjectMapper mapper2 = new ObjectMapper(); SimpleModule module2 = new SimpleModule(); module2.addDeserializer(List.class, new CityJsonDeSerializer()); mapper2.registerModule(module2); List<City> list = mapper2.readValue(listJsonStr, new TypeReference<List<City>>(){} ); for (City city: list) { System.out.println("id:"+city.getId()+" cityName:"+city.getCityName()); } }
也可以简单一点,使用注解,省去在ObjectMapper 中注册SimpleModule
import com.fasterxml.jackson.databind.annotation.JsonSerialize;@JsonSerialize(using=CityJsonSerializer.class)public class City { ...}
运行结果:
[{"cityName":"gz"},{"id":2,"cityName":"dg"}]id:null cityName:gzid:2 cityName:dg
###3.Tree Mode
如果不想为Json结构写一个class的话,Tree Mode是一个很好的选择。
生成json:
@Test public void TreeMode2Json() throws IOException{ //创建一个节点工厂,为我们提供所有节点 JsonNodeFactory factory = new JsonNodeFactory(false); //创建一个json factory来写tree modle为json JsonFactory jsonFactory = new JsonFactory(); //创建一个json生成器 JsonGenerator generator = jsonFactory.createGenerator(new FileWriter(new File("country2.json"))); //注意,默认情况下对象映射器不会指定根节点,下面设根节点为country ObjectMapper mapper = new ObjectMapper(); ObjectNode country = factory.objectNode(); country.put("id", 1); country.put("countryName","China"); country.put("establishTime", "1949-10-01"); ArrayNode provinces = factory.arrayNode(); ObjectNode province = factory.objectNode(); ObjectNode city1 = factory.objectNode(); city1.put("id", 1); city1.put("cityName", "gz"); ObjectNode city2 = factory.objectNode(); city2.put("id", 1); city2.put("cityName", "dg"); ArrayNode cities = factory.arrayNode(); cities.add(city1).add(city2); province.put("cities", cities); provinces.add(province); country.put("provinces",provinces); ArrayNode lakes = factory.arrayNode(); lakes.add("QingHai Lake").add("Poyang Lake").add("Dongting Lake").add("Taihu Lake"); country.put("lakes",lakes); ObjectNode forest = factory.objectNode(); forest.put("no.1","dxal"); forest.put("no.2", "xxal"); country.put("forest", forest); mapper.setSerializationInclusion(Include.NON_EMPTY); // 配置mapper忽略空属性 mapper.writeTree(generator, country); }
结果:
{ "id":1, "countryName":"China", "establishTime":"1949-10-01", "provinces":[ {"cities":[ {"id":1,"cityName":"gz"}, {"id":1,"cityName":"dg"} ] } ], "lakes":["QingHai Lake","Poyang Lake","Dongting Lake","Taihu Lake"], "forest":{"no.1":"dxal","no.2":"xxal"}}
读取json:
@Testpublic void TreeModeReadJson() throws IOException{ ObjectMapper mapper = new ObjectMapper(); // Jackson提供一个树节点被称为"JsonNode",ObjectMapper提供方法来读json作为树的JsonNode根节点 JsonNode node = mapper.readTree(new File("country2.json")); // 看看根节点的类型 System.out.println("node JsonNodeType:"+node.getNodeType()); System.out.println("---------得到所有node节点的子节点名称----------------------"); Iterator<String> fieldNames = node.fieldNames(); while (fieldNames.hasNext()) { String fieldName = fieldNames.next(); System.out.print(fieldName+" "); } System.out.println("\n---------------------------------------------------"); JsonNode lakes = node.get("lakes"); System.out.println("lakes:"+lakes+" JsonNodeType:"+lakes.getNodeType()); }
运行结果:
node JsonNodeType:OBJECT---------得到所有node节点的子节点名称-------------------------id countryName establishTime provinces lakes forest -----------------------------------------------------lakes:["QingHai Lake","Poyang Lake","Dongting Lake","Taihu Lake"] JsonNodeType:ARRAY
结束
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://blog.csdn.net/gjb724332682/article/details/51586701#
http://blog.csdn.net/java_huashan/article/details/46375857
- Java解析json(二):jackson
- java json解析-jackson
- java json解析-jackson
- java json解析-jackson
- java json解析fastjson jackson
- Java解析json——Jackson
- Java、Json转换方式之二:Jackson
- jackson解析 json字符串
- Jackson解析JSON例子
- Jackson解析JSON例子
- jackson框架解析json
- Jackson解析JSON数据
- Json解析工具Jackson
- Jackson解析JSON例子
- Json解析工具Jackson
- JSON解析之Jackson
- JSON的解析[Jackson]
- jackson解析json
- 使用Maven管理Jar包
- Chapter_2 算法分析:快速求幂法
- python 操作数据库
- VO对象和PO对象的区别
- XpSp3(未开启PAE模式)内存管理之系统PTE区域 上
- Java解析json(二):jackson
- py-faster-rcnn制作自己的数据集做目标检测
- Android事件传递
- 转载:分享这五年电商网站网络推广的深刻经历
- Android Activity堆栈详解
- Android中APK直接通过JNI访问驱动
- Java解析json(三):fastjson
- 使用Enumeration和Iterator遍历集合类详解
- 详解 QT 布局管理界面 图文并茂