JackSon的几种用法

JackSon介绍

本文使用的JackSon版本为2.9.6。

JackSon是解析JSON和XML的一个框架,优点是简单易用,性能较高。

JackSon处理JSON的方式

JackSon提供了三种JSON的处理方式。分别是数据绑定,树模型,流式API。下面会分别介绍这三种方式。

JackSon数据绑定

数据绑定用于JSON转化,可以将JSON与POJO对象进行转化。数据绑定有两种,简单数据绑定和完整数据绑定。

完整数据绑定

package com.xymxyg.json;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;

/**
 * @author guangsheng.tang
 * 下面是最常用的场景,将json字符串映射为对象,或者是将对象转化为json字符串。这是完整数据绑定。
 缺点:这种方法十分方便,但是扩展性不强,增加一个字段便要修改POJO对象,这个操作有一定风险性。并且解析的时候,如果json缺少POJO中的某字段,映射出的对象对应值默认为null,直接使用有一定风险。如果json对象多了某一字段,解析过程中会抛出UnrecognizedPropertyException异常。并且如果json较为复杂的话,POJO对象会显得特别臃肿。
 */
public class CompleteDataBind {
    public static void main(String[] args) throws IOException {
       String s = "{\"id\": 1,\"name\": \"小明\",\"array\": [\"1\", \"2\"]}";
        ObjectMapper mapper = new ObjectMapper();
        //Json映射为对象
        Student student = mapper.readValue(s, Student.class);
        //对象转化为Json
        String json = mapper.writeValueAsString(student);
        System.out.println(json);
        System.out.println(student.toString());
    }
}
package com.xymxyg.json;

/**
 * @author guangsheng.tang
 */
public class Student {
    private int id;
    private String  name;
    private String sex;
    private ArrayList<String> array;
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public ArrayList<String> getArray() {
        return array;
    }

    public void setArray(ArrayList<String> array) {
        this.array = array;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", array=" + Arrays.toString(array.toArray()) +
                '}';
    }
}

简单数据绑定

简单数据绑定就是将json字符串映射为java核心的数据类型。

json类型Java类型
objectLinkedHashMap
arrayArrayList
stringString
numberInteger,Long,Double
true|falseBoolean
nullnull

下面演示一个例子,将json转化为一个Map。通过Map来读取。

package com.xymxyg.json;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @author guangsheng.tang
 * 简单数据绑定的示例,不用POJO对象,直接映射为一个Map,然后从Map中获取。
 */
public class SimpleDataBind {
    public static void main(String[] args) throws IOException {
        Map<String, Object> map = new HashMap<>(16);
        String s = "{\"id\": 1,\"name\": \"小明\",\"array\": [\"1\", \"2\"]," +
                "\"test\":\"I'm test\",\"base\": {\"major\": \"物联网\",\"class\": \"3\"}}";
        ObjectMapper mapper = new ObjectMapper();
        map = mapper.readValue(s, map.getClass());
        //获取id
        Integer studentId = (Integer) map.get("id");
        System.out.println(studentId);
        //获取数据
        ArrayList list = (ArrayList) map.get("array");
        System.out.println(Arrays.toString(list.toArray()));
        //新增加的字段可以很方便的处理
        String test = (String) map.get("test");
        System.out.println(test);
        //不存在的返回null
        String notExist = (String) map.get("notExist");
        System.out.println(notExist);
        //嵌套的对象获取
        Map base = (Map) map.get("base");
        String major = (String) base.get("major");
        System.out.println(major);
    }
}

树模型

针对JackSon的树模型结构,我下面写了一个比较完善的例子。同样Java树模型有优点,也有缺点。

package com.xymxyg.json;

import com.fasterxml.jackson.core.JsonPointer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import java.io.IOException;

/**
 * @author guangsheng.tang
 * JackSon树模型结构,可以通过get,JsonPointer等进行操作,适合用来获取大Json中的字段,比较灵活。缺点是如果需要获取的内容较多,
 * 会显得比较繁琐。
 */
public class TreeModel {
    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        //以下是对象转化为Json
        JsonNode root = mapper.createObjectNode();
        ((ObjectNode) root).putArray("array");
        ArrayNode arrayNode = (ArrayNode) root.get("array");
        ((ArrayNode) arrayNode).add("args1");
        ((ArrayNode) arrayNode).add("args2");
        ((ObjectNode) root).put("name", "小红");
        String json = mapper.writeValueAsString(root);
        System.out.println("使用树型模型构建的json:"+json);
        //以下是树模型的解析Json
        String s = "{\"id\": 1,\"name\": \"小明\",\"array\": [\"1\", \"2\"]," +
                "\"test\":\"I'm test\",\"nullNode\":null,\"base\": {\"major\": \"物联网\",\"class\": \"3\"}}";
        //读取rootNode
        JsonNode rootNode = mapper.readTree(s);
        //通过path获取
        System.out.println("通过path获取值:" + rootNode.path("name").asText());
        //通过JsonPointer可以直接按照路径获取
        JsonPointer pointer = JsonPointer.valueOf("/base/major");
        JsonNode node = rootNode.at(pointer);
        System.out.println("通过at获取值:" + node.asText());
        //通过get可以取对应的value
        JsonNode classNode = rootNode.get("base");
        System.out.println("通过get获取值:" + classNode.get("major").asText());

        //获取数组的值
        System.out.print("获取数组的值:");
        JsonNode arrayNode2 = rootNode.get("array");
        for (int i = 0; i < arrayNode2.size(); i++) {
            System.out.print(arrayNode2.get(i).asText()+" ");
        }
        System.out.println();
        //path和get方法看起来很相似,其实他们的细节不同,get方法取不存在的值的时候,会返回null。而path方法会
        //返回一个"missing node",该"missing node"的isMissingNode方法返回值为true,如果调用该node的asText方法的话,
        // 结果是一个空字符串。
        System.out.println("get方法取不存在的节点,返回null:" + (rootNode.get("notExist") == null));
        JsonNode notExistNode = rootNode.path("notExist");
        System.out.println("notExistNode的value:" + notExistNode.asText());
        System.out.println("isMissingNode方法返回true:" + notExistNode.isMissingNode());

        //当key存在,而value为null的时候,get和path都会返回一个NullNode节点。
        System.out.println(rootNode.get("nullNode") instanceof NullNode);
        System.out.println(rootNode.path("nullNode") instanceof NullNode);
    }
}

流式API

流式API是一套比较底层的API,速度快,但是使用起来特别麻烦。它主要是有两个核心类,一个是JsonGenerator,用来生成json,另一个是JsonParser,用来读取json内容。话不多说,直接上代码演示。

package com.xymxyg.json;

import com.fasterxml.jackson.core.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * @author guangsheng.tang
 *  JsonParser和Generator的优点是速度快,缺点是写起来真的很复杂。
 */
public class StreamApi {
    public static void main(String[] args) throws IOException {
        JsonFactory factory = new JsonFactory();
        String s = "{\"id\": 1,\"name\": \"小明\",\"array\": [\"1\", \"2\"]," +
                "\"test\":\"I'm test\",\"nullNode\":null,\"base\": {\"major\": \"物联网\",\"class\": \"3\"}}";

        //这里就举一个比较简单的例子,Generator的用法就是一个一个write即可。
        File file = new File("/json.txt");
        JsonGenerator jsonGenerator = factory.createGenerator(file, JsonEncoding.UTF8);
        //对象开始
        jsonGenerator.writeStartObject();
        //写入一个键值对
        jsonGenerator.writeStringField("name", "小光");
        //对象结束
        jsonGenerator.writeEndObject();
        //关闭jsonGenerator
        jsonGenerator.close();
        //读取刚刚写入的json
        FileInputStream inputStream = new FileInputStream(file);
        int i = 0;
        final int SIZE = 1024;
        byte[] buf = new byte[SIZE];
        StringBuilder sb = new StringBuilder();
        while ((i = inputStream.read(buf)) != -1) {
            System.out.println(new String(buf,0,i));
        }
        inputStream.close();


        //JsonParser解析的时候,思路是把json字符串根据边界符分割为若干个JsonToken,这个JsonToken是一个枚举类型。
        //下面这个小例子,可以看出JsonToken是如何划分类型的。
        JsonParser parser = factory.createParser(s);
        while (!parser.isClosed()){
            JsonToken token = parser.currentToken();
            System.out.println(token);
            parser.nextToken();
        }

        JsonParser jsonParser = factory.createParser(s);
        //下面是一个解析的实例
        while (!jsonParser.isClosed()) {
            JsonToken token  = jsonParser.nextToken();
            if (JsonToken.FIELD_NAME.equals(token)) {
                String currentName = jsonParser.currentName();
                token = jsonParser.nextToken();
                if ("id".equals(currentName)) {
                    System.out.println("id:" + jsonParser.getValueAsInt());
                } else if ("name".equals(currentName)) {
                    System.out.println("name:" + jsonParser.getValueAsString());
                } else if ("array".equals(currentName)) {
                    token = jsonParser.nextToken();
                    while (!JsonToken.END_ARRAY.equals(token)) {
                        System.out.println("array:" + jsonParser.getValueAsString());
                        token = jsonParser.nextToken();
                    }
                }
            }
        }
    }

}

JackSon的常用注解

JackSon提供了一些的注解,可以用在类上或者是在字段上。通常是数据绑定的时候使用。下面几个是最常用的几个

@JsonInclude(Include.NON_EMPTY)

仅在属性不为空时序列化此字段,对于字符串,即null或空字符串

@JsonIgnore

序列化时忽略此字段

@JsonProperty(value = “user_name”)

指定序列化时的字段名,默认使用属性名

总结

JackSon使用起来还是十分方便的,提供的功能也很多,在使用的时候,需要结合自己的业务场景,选择合适的解析方式。

参考资料

http://blog.lifw.org/post/63088058v
https://www.yiibai.com/jackson/

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值