浅谈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类型
object LinkedHashMap
array ArrayList
string String
number Integer,Long,Double
true|false Boolean
null null

下面演示一个例子,将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/

到此这篇关于浅谈JackSon的几种用法的文章就介绍到这了,更多相关JackSon 用法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Jackson的用法实例分析

    通俗的来说,Jackson是一个 Java 用来处理 JSON 格式数据的类库,其性能非常好.本文就来针对Jackson的用法做一个较为详细的实例分析.具体如下: 一.简介 Jackson具有比较高的序列化和反序列化效率,据测试,无论是哪种形式的转换,Jackson > Gson > Json-lib,而且Jackson的处理能力甚至高出Json-lib近10倍左右,且正确性也十分高.相比之下,Json-lib似乎已经停止更新,最新的版本也是基于JDK15,而Jackson的社区则较为活跃.

  • 关于Jackson的JSON工具类封装 JsonUtils用法

    直接上代码,都有注释,一看就懂,完全满足日常开发需求 import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.Deserializa

  • Java中Jackson快速入门

    Java生态圈中有很多处理JSON和XML格式化的类库,Jackson是其中比较著名的一个.虽然JDK自带了XML处理类库,但是相对来说比较低级,使用本文介绍的Jackson等高级类库处理起来会方便很多. 引入类库 由于Jackson相关类库按照功能分为几个相对独立的,所以需要同时引入多个类库,为了方便我将版本号单独提取出来设置,相关Gradle配置如下. ext { jacksonVersion = '2.9.5' } dependencies { compile group: 'com.fa

  • 浅谈JackSon的几种用法

    JackSon介绍 本文使用的JackSon版本为2.9.6. JackSon是解析JSON和XML的一个框架,优点是简单易用,性能较高. JackSon处理JSON的方式 JackSon提供了三种JSON的处理方式.分别是数据绑定,树模型,流式API.下面会分别介绍这三种方式. JackSon数据绑定 数据绑定用于JSON转化,可以将JSON与POJO对象进行转化.数据绑定有两种,简单数据绑定和完整数据绑定. 完整数据绑定 package com.xymxyg.json; import com

  • 浅谈SpringMVC中的session用法及细节记录

    前言 初学SpringMVC,最近在给公司做的系统做登录方面,需要用到session. 在网上找了不少资料,大致提了2点session保存方式: 1.javaWeb工程通用的HttpSession 2.SpringMVC特有的@SessionAttributes 我个人比较关注@SessionAttributes的用法,毕竟现在是在用SpringMVC嘛.但是我看网上那些文章,基本都是只说明了基础用法,详细的使用和细节却基本没有,我想这是不够的,所以我自己做了一些测试,然后整理了下代码做了个de

  • 浅谈MyBatis循环Map(高级用法)

    今天遇到一个比较特殊的业务,需要对传入的Map数据在映射文件中进行遍历,在之前的学习中,我们也知道MyBatis有默认对集合的操作list和array,但是没有默认的map,所有不能直接写collection="map",如果这么处理,它会当成是根据map.get("map")获取传递value只,==大部分情况下是一个map中是不会有"map"这个key的,于是就是报错==.如果你想用map标识来获取参数map,就需要保证传入的Map参数有@P

  • 浅谈Spring的两种事务定义方式

    一.声明式 这种方法不需要对原有的业务做任何修改,通过在XML文件中定义需要拦截方法的匹配即可完成配置,要求是,业务处理中的方法的命名要有规律,比如setXxx,xxxUpdate等等.详细配置如下: <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="

  • 浅谈Spring的两种配置容器

    Spring提供了两种容器类型 SpringIOC容器是一个IOC Service Provider.提供了两种容器类型:BeanFactory和ApplicationContext.Spring的IOC容器是一个提供IOC支持的轻量级容器.除了基本的ioc支持,它作为轻量级容器还提供了IOC之外的支持. BeanFactory BeanFactory是基础类型IOC容器.顾名思义,就是生产Bean的工厂.能够提供完整的IOC服务.没有特殊指定的话,其默认采用延迟初始化策略.只有当客户端对象需要

  • 浅谈Java的两种多线程实现方式

    本文介绍了浅谈Java的两种多线程实现方式,分享给大家.具有如下: 一.创建多线程的两种方式 Java中,有两种方式可以创建多线程: 1 通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2 通过实现Runnable接口,实例化Thread类 在实际应用中,我们经常用到多线程,如车站的售票系统,车站的各个售票口相当于各个线程.当我们做这个系统的时候可能会想到两种方式来实现,继承Thread类或实现Runnable接口,现在看一下这两种方式实现的两种结果. 程序1

  • 浅谈线程的几种可用状态

    1. 新建( new ):新创建了一个线程对象. 2. 可运行( runnable ):线程对象创建后,其他线程(比如 main 线程)调用了该对象 的 start ()方法.该状态的线程位于可运行线程池中,等待被线程调度选中,获 取 cpu 的使用权 . 3. 运行( running ):可运行状态( runnable )的线程获得了 cpu 时间片( timeslice ) ,执行程序代码. 4. 阻塞( block ):阻塞状态是指线程因为某种原因放弃了 cpu 使用权,也即让出了 cpu

  • 浅谈numpy中linspace的用法 (等差数列创建函数)

    linspace 函数 是创建等差数列的函数, 最好是在 Matlab 语言中见到这个函数的,近期在学习Python 中的 Numpy, 发现也有这个函数,以下给出自己在学习过程中的一些总结. (1)指定起始点 和 结束点. 默认 等差数列个数为 50. (2)指定等差数列个数 (3)如果数列的元素个数指定, 可以设置 结束点 状态. endpoint : bool, optional If True, stop is the last sample. Otherwise, it is not

  • 浅谈js函数三种定义方式 & 四种调用方式 & 调用顺序

    在Javascript定义一个函数一般有如下三种方式: 函数关键字(function)语句: function fnMethodName(x){alert(x);} 函数字面量(Function Literals): var fnMethodName = function(x){alert(x);} Function()构造函数: var fnMethodName = new Function('x','alert(x);') // 由Function构造函数的参数个数可变.最后一个参数写函数体

  • 浅谈vim的四种模式及模式切换

    vim和记事本或WORD不一样,不是一打开后就可以输入文字,此时它处于正常模式. vim一共有4个模式: • 正常模式 (Normal-mode) • 插入模式 (Insert-mode) • 命令模式 (Command-mode) • 可视模式 (Visual-mode) 正常模式 启动vim后默认处于正常模式.不论位于什么模式,按下<Esc>键(有时需要按两下)都会进入正常模式. 插入模式 在正常模式中按下i, I, a, A等键,会进入插入模式.现在只用记住按i键会进行插入模式.在插入模

随机推荐