Java中Jackson包解析Json格式总结

Jackson框架是基于Java平台的一套数据处理工具,它包含了3个核心库:streaming,databind,annotations,被称为“最好的Java Json解析器”。

下载

Jackson的jar包下载地址:http://jackson.codehaus.org/1.7.6/jackson-all-1.7.6.jar

下载完毕导入jar包,依赖jackon的三个核心类库:
jackson-core-2.5.3.jar    定义了底层的streaming API和实现了Json特性。
jackson-annotations-2.5.3.jar    包含了标准的Jackson注解。
jackson-databind-2.5.3.jar    实现了数据绑定和对象序列化,它依赖于streaming和annotations的包。

解析Json的3种方式

流式API(Streaming API)

Jackson API提供了token对每个Json对象,例如,Json开始符号“{”是token指向的第一个解析的对象,key:value键值对是另一个单独的对象。这个API很强大,但也需要编写大量代码。不推荐使用,平时更多的是使用DataBinding和TreeModel来处理json。

//测试json1
{
    "country_id": "China",
    "provinces": [{
        "name": "Shanxi",
        "population": 33750000
    }]
}
//查找json中population的值
package com.jackson.json.streaming;
import java.io.File;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
public class StreamParserJson {
    public static void main(String[] args) throws JsonParseException,
    IOException {
        JsonFactory factory = new JsonFactory();
        // 从JsonFactory创建JsonParser解析器的实例  
        JsonParser parser = factory.createParser(new File("测试json1.json"));
        while (!parser.isClosed()) {
            // 得到一个token,第一次遍历时,token指向json文件中第一个符号"{"  
            JsonToken token = parser.nextToken();
            if (token == null) {
                break;
            }
            // 我们只查找 country3.json中的"population"字段的值,能体现解析的流程就可以了  
            // 当key是provinces时,我们进入provinces,查找population  
            if (JsonToken.FIELD_NAME.equals(token) && "provinces".equals(parser.getCurrentName())) {
                token = parser.nextToken();
                if (!JsonToken.START_ARRAY.equals(token)) {
                    break;
                }
                // 此时,token指向的应该是"{"  
                token = parser.nextToken();
                if (!JsonToken.START_OBJECT.equals(token)) {
                    break;
                }
                while (true) {
                    token = parser.nextToken();
                    if (token == null) {
                        break;
                    }
                    if (JsonToken.FIELD_NAME.equals(token) && "population".equals(parser.getCurrentName())) {
                        token = parser.nextToken();
                        System.out.println(parser.getCurrentName() + " : " + parser.getIntValue());
                    }
                }
            }
        }
    }
}

运行结果:

population : 33750000  

树模型(Tree Model)

Tree Model是最灵活的处理json的方式

//测试json2
{
    "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
    }
}
//解析json字符串进行反序列化
public static void main(String[] args) throws Exception {
    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 is container Node ? " + node.isContainerNode());
    // 得到所有node节点的子节点名称  
    System.out.println("---------得到所有node节点的子节点名称-------------------------");
    Iterator < String > fieldNames = node.fieldNames();
    while (fieldNames.hasNext()) {
        String fieldName = fieldNames.next();
        System.out.print(fieldName + " ");
    }
    System.out.println("\n-----------------------------------------------------");
    // as.Text的作用是有值返回值,无值返回空字符串  
    JsonNode country_id = node.get("country_id");
    System.out.println("country_id:" + country_id.asText() + " JsonNodeType:" + country_id.getNodeType());

    JsonNode birthDate = node.get("birthDate");
    System.out.println("birthDate:" + birthDate.asText() + " JsonNodeType:" + birthDate.getNodeType());

    JsonNode nation = node.get("nation");
    System.out.println("nation:" + nation + " JsonNodeType:" + nation.getNodeType());

    JsonNode lakes = node.get("lakes");
    System.out.println("lakes:" + lakes + " JsonNodeType:" + lakes.getNodeType());

    JsonNode provinces = node.get("provinces");
    System.out.println("provinces JsonNodeType:" + provinces.getNodeType());

    boolean flag = true;
    for (JsonNode provinceElements: provinces) {
        //为了避免provinceElements多次打印,用flag控制打印,能体现provinceElements的JsonNodeType就可以了  
        if (flag) {
            System.out.println("provinceElements JsonNodeType:" + provinceElements.getNodeType());
            System.out.println("provinceElements is container node? " + provinceElements.isContainerNode());
            flag = false;
        }
        Iterator < String > provinceElementFields = provinceElements.fieldNames();
        while (provinceElementFields.hasNext()) {
            String fieldName = (String) provinceElementFields.next();
            String province;
            if ("population".equals(fieldName)) {
                province = fieldName + ":" + provinceElements.get(fieldName).asInt();
            } else {
                province = fieldName + ":" + provinceElements.get(fieldName).asText();
            }
            System.out.println(province);
        }
    }
}

运行结果:

node JsonNodeType:OBJECT  
node is container Node ? true  
---------得到所有node节点的子节点名称-------------------------  
country_id birthDate nation lakes provinces traffic   
-----------------------------------------------------  
country_id:China JsonNodeType:STRING  
birthDate:1949-10-01 JsonNodeType:STRING  
nation:["Han","Meng","Hui","WeiWuEr","Zang"] JsonNodeType:ARRAY  
lakes:["QingHai Lake","Poyang Lake","Dongting Lake","Taihu Lake"] JsonNodeType:ARRAY  
provinces JsonNodeType:ARRAY  
provinceElements JsonNodeType:OBJECT  
provinceElements is container node? true  
name:Shanxi  
population:37751200  
name:ZheJiang  
population:55080000  

数据绑定(Data Binding)

Data Binding是最常用的解析json方式

//country.json
{  
  "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  
  }  
}  
//Province.java
public class Province {  
    public String name;  
    public int population;  
    public String[] city;     
}  
//Country.java
public class Country {  
    // 注意:被序列化的bean的private属性字段需要创建getter方法或者属性字段应该为public  
    private String country_id;  
    private Date birthDate;  
    private List<String> nation = new ArrayList<String>();  
    private String[] lakes;  
    private List<Province> provinces = new ArrayList<Province>();  
    private Map<String, Integer> traffic = new HashMap<String, Integer>();  
  
    public Country() {  
        // TODO Auto-generated constructor stub  
    }  
  
    public Country(String countryId) {  
        this.country_id = countryId;  
    }  
  
    public String getCountry_id() {  
        return country_id;  
    }  
  
    public void setCountry_id(String country_id) {  
        this.country_id = country_id;  
    }  
  
    public Date getBirthDate() {  
        return birthDate;  
    }  
  
    public void setBirthDate(Date birthDate) {  
        this.birthDate = birthDate;  
    }  
  
    public List<String> getNation() {  
        return nation;  
    }  
  
    public void setNation(List<String> nation) {  
        this.nation = nation;  
    }  
  
    public String[] getLakes() {  
        return lakes;  
    }  
  
    public void setLakes(String[] lakes) {  
        this.lakes = lakes;  
    }  
  
    public Integer get(String key) {  
        return traffic.get(key);  
    }  
  
    public Map<String, Integer> getTraffic() {  
        return traffic;  
    }  
  
    public void setTraffic(Map<String, Integer> traffic) {  
        this.traffic = traffic;  
    }  
  
    public void addTraffic(String key, Integer value) {  
        traffic.put(key, value);  
    }  
  
    public List<Province> getProvinces() {  
        return provinces;  
    }  
  
    public void setProvinces(List<Province> provinces) {  
        this.provinces = provinces;  
    }  
  
    @Override  
    public String toString() {  
        return "Country [country_id=" + country_id + ", birthDate=" + birthDate  
                + ", nation=" + nation + ", lakes=" + Arrays.toString(lakes)  
                + ", province=" + provinces + ", traffic=" + traffic + "]";  
    }  
  
}  

/** 
 * 解析Json字符串反序列化为Java对象 
 */  
public static void main(String[] args) throws Exception {
    //ObjectMapper类用序列化与反序列化映射器  
    ObjectMapper mapper = new ObjectMapper();
    File json = new File("country.json");
    //当反序列化json时,未知属性会引起的反序列化被打断,这里我们禁用未知属性打断反序列化功能,  
    //因为,例如json里有10个属性,而我们的bean中只定义了2个属性,其它8个属性将被忽略  
    mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

    //从json映射到java对象,得到country对象后就可以遍历查找,下面遍历部分内容,能说明问题就可以了  
    Country country = mapper.readValue(json, Country.class);
    System.out.println("country_id:" + country.getCountry_id());
    //设置时间格式,便于阅读  
    SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
    String birthDate = dateformat.format(country.getBirthDate());
    System.out.println("birthDate:" + birthDate);

    List < Province > provinces = country.getProvinces();
    for (Province province: provinces) {
        System.out.println("province:" + province.name + "\n" + "population:" + province.population);
    }

运行结果:

country_id:China  
birthDate:1949-10-01  
province:Shanxi  
population:37751200  
province:ZheJiang  
population:55080000 

总结

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

2. Databinding处理Json是最常用的json处理方式,生成json时,创建相关的java对象,并根据json内容结构把java对象组装起来,最后调用writeValue方法即可生成json,解析时,就更简单了,直接把json映射到相关的java对象,然后就可以遍历java对象来获取值了。

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