Jackson使用(超详细)

Jackson使用详解

1、介绍

Spring MVC 默认采用Jackson解析Json,尽管还有一些其它同样优秀的json解析工具,例如Fast Json、GSON,但是出于最小依赖的考虑,也许Json解析第一选择就应该是Jackson。

简介

Jackson 是当前用的比较广泛的,用来序列化和反序列化 json 的 Java 的开源框架。Jackson 社区相对比较活跃,更新速度也比较快, 从 Github 中的统计来看,Jackson 是最流行的 json 解析器之一 。 Spring MVC 的默认 json 解析器便是 Jackson。 Jackson 优点很多。 Jackson 所依赖的 jar 包较少 ,简单易用。与其他 Java 的 json 的框架 Gson 等相比, Jackson 解析大的 json 文件速度比较快;Jackson 运行时占用内存比较低,性能比较好;Jackson 有灵活的 API,可以很容易进行扩展和定制。

Jackson 的 1.x 版本的包名是 org.codehaus.jackson ,当升级到 2.x 版本时,包名变为 com.fasterxml.jackson。

Jackson 的核心模块由三部分组成。

  • jackson-core,核心包,提供基于"流模式"解析的相关 API,它包括 JsonPaser 和 JsonGenerator。 Jackson 内部实现正是通过高性能的流模式 API 的 JsonGenerator 和 JsonParser 来生成和解析 json。
  • jackson-annotations,注解包,提供标准注解功能;
  • jackson-databind ,数据绑定包, 提供基于"对象绑定" 解析的相关 API ( ObjectMapper ) 和"树模型" 解析的相关 API (JsonNode);基于"对象绑定" 解析的 API 和"树模型"解析的 API 依赖基于"流模式"解析的 API。

源码地址FasterXML/jackson

2、使用

导入依赖

两种方式:一种是直接引入spring-boot-starter-web内嵌了jackson依赖,一种是引入jackson依赖

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>2.7.0</version>
    </dependency>

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.9.6</version>
</dependency>

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.9.6</version>
</dependency>

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.6</version>
</dependency>

解释

jackson-databind 依赖 jackson-core 和 jackson-annotations,所以可以只显示地添加jackson-databind依赖,jackson-core 和 jackson-annotations 也随之添加到 Java 项目工程中。

3、ObjectMapper 对象映射器

ObjectMapper 是 Jackson 库中最常用的一个类,使用它可以进行 Java 对象和 JSON 字符串之间快速转换。如果你用过 FastJson,那么 Jackson 中的 ObjectMapper 就如同 FastJson 中的 JSON 类。

这个类中有一些常用的方法:

  • readValue() 方法可以进行 JSON 的反序列化操作,比如可以将字符串、文件流、字节流、字节数组等将常见的内容转换成 Java 对象。
  • writeValue() 方法可以进行 JSON 的序列化操作,可以将 Java 对象转换成 JSON 字符串。

大多数情况下,ObjectMapper 的工作原理是通过 Java Bean 对象的 Get/Set 方法进行转换时映射的,所以正确编写 Java 对象的 Get/Set 方法尤为重要,不过 ObjectMapper 也提供了诸多配置,比如可以通过配置或者注解的形式对 Java 对象和 JSON 字符串之间的转换过程进行自定义。这些在下面部分都会介绍到。

4、Jackson JSON Api操作

ObjectMapper如何匹配JSON对象的字段和Java对象的属性

默认情况下,Jackson通过将JSON字段的名称与Java对象中的getter和setter方法进行匹配,将JSON对象的字段映射到Java对象中的属性。 Jackson删除了getter和setter方法名称的“ get”和“ set”部分,并将其余名称的第一个字符转换为小写。

例如,名为brand的JSON字段与名为getBrand()和setBrand()的Java getter和setter方法匹配。 名为engineNumber的JSON字段将与名为getEngineNumber()和setEngineNumber()的getter和setter匹配。

如果需要以其他方式将JSON对象字段与Java对象字段匹配,则需要使用自定义序列化器和反序列化器,或者使用一些Jackson注解。

4.1、从JSON中获取Java对象

4.1.1、JSON 字符输入流–>Java对象

重点使用api:objectMapper.readValue(json, Person.class);

//java对象测试
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private String name;
    private int age;
    private List<String> skillsList;
}
//java对象转换为json格式
public class JsonToJava {

    public static void main(String[] args) throws JsonProcessingException {
        String json = "{\"name\":\"swx\",\"age\":18,\"skillsList\":[\"java\",\"python\",\"php\"]}";
        ObjectMapper objectMapper = new ObjectMapper();
        Person person = objectMapper.readValue(json, Person.class);
        //Person(name=swx, age=18, skillsList=[java, python, php])
        System.out.println(person);
    }
}

还可以从通过Reader实例加载的JSON中读取对象。示例如下:

//java对象转换为json格式
public class JsonToJava {

    public static void main(String[] args) throws IOException {
        String json = "{\"name\":\"swx\",\"age\":18,\"skillsList\":[\"java\",\"python\",\"php\"]}";
        ObjectMapper objectMapper = new ObjectMapper();
        Reader reader = new StringReader(json);
        Person person = objectMapper.readValue(reader, Person.class);
        //Person(name=swx, age=18, skillsList=[java, python, php])
        System.out.println(person);
    }
}
4.1.2、JSON文件–>Java对象

在src下新建一个test.json文件

{
  "name" : "swx",
  "age" : 19,
  "skillsList" : [
    "java",
    "c++"
  ]
}
//JSON文件-->Java对象
public class JsonToJava2 {

    public static void main(String[] args) throws IOException {
        File file = new File("src/test.json");
        ObjectMapper objectMapper = new ObjectMapper();
        Person person = objectMapper.readValue(file, Person.class);
        //Person(name=swx, age=19, skillsList=[java, c++])
        System.out.println(person);
    }
}
4.1.3、JSON via URL—>Java对象
ObjectMapper objectMapper = new ObjectMapper();

URL url = new URL("file:data/car.json");

Car car = objectMapper.readValue(url, Car.class);

示例使用文件URL,也可以使用HTTP URL(类似于http://jenkov.com/some-data.json)。

4.1.4、JSON字节输入流–>Java对象

也可以使用ObjectMapper通过InputStream从JSON读取对象。 这是一个从InputStream读取JSON的示例:

json文件

{
  "name" : "zxy",
  "age" : 66,
  "skillsList" : [
    "java",
    "python"
  ]
}
//JSON字节输入流-->Java对象
public class JsonToJava3 {

    public static void main(String[] args) throws IOException {
        FileInputStream in = new FileInputStream("src/test2.json");
        ObjectMapper objectMapper = new ObjectMapper();
        Person person = objectMapper.readValue(in, Person.class);
        //Person(name=zxy, age=66, skillsList=[java, python])
        System.out.println(person);
    }
}
4.1.5、JSON二进制数组–>Java对象
//JSON二进制数组-->Java对象
public class JsonToJava4 {

    public static void main(String[] args) throws IOException {
        String json = "{\"name\":\"swx\",\"age\":18,\"skillsList\":[\"java\",\"python\",\"php\"]}";
        byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
        ObjectMapper objectMapper = new ObjectMapper();
        Person person = objectMapper.readValue(bytes, Person.class);
        //Person(name=swx, age=18, skillsList=[java, python, php])
        System.out.println(person);
    }
}
4.1.6、JSON数组字符串–>Java对象数组
//JSON数组字符串-->Java对象数组
public class JsonToJava5 {

    public static void main(String[] args) throws IOException {
        String json = "[{\"name\":\"swx\",\"age\":18,\"skillsList\":[\"java\",\"python\",\"php\"]},{\"name\":\"博尔特\",\"age\":55,\"skillsList\":[\"短跑\",\"两百米跑\"]}]";
        ObjectMapper objectMapper = new ObjectMapper();
        Person[] person = objectMapper.readValue(json, Person[].class);
        //Person(name=swx, age=18, skillsList=[java, python, php])
        //Person(name=博尔特, age=55, skillsList=[短跑, 两百米跑])
        for (Person person1 : person) {
            System.out.println(person1);
        }
    }
}
4.1.6、JSON数组字符串–>List

Jackson ObjectMapper还可以从JSON数组字符串读取对象的Java List。 这是从JSON数组字符串读取对象列表的示例:

//JSON数组字符串-->List
public class JsonToJava6 {

    public static void main(String[] args) throws IOException {
        String json = "[{\"name\":\"swx\",\"age\":18,\"skillsList\":[\"java\",\"python\",\"php\"]}," +
                "{\"name\":\"博尔特\",\"age\":55,\"skillsList\":[\"短跑\",\"两百米跑\"]}," +
                "{\"name\":\"迪迦\",\"age\":1500,\"skillsList\":[\"打怪兽\",\"射击\"]}]";
        ObjectMapper objectMapper = new ObjectMapper();
        List<Person> personList = objectMapper.readValue(json, new TypeReference<List<Person>>() {
        });
        //Person(name=swx, age=18, skillsList=[java, python, php])
        //Person(name=博尔特, age=55, skillsList=[短跑, 两百米跑])
        //Person(name=迪迦, age=1500, skillsList=[打怪兽, 射击])
        personList.forEach(item -> {
            System.out.println(item);
        });
    }
}
4.1.6、JSON字符串–>Map

Jackson ObjectMapper还可以从JSON字符串读取Java Map。 如果事先不知道将要解析的确切JSON结构,这种方法是很有用的。 通常,会将JSON对象读入Java Map。 JSON对象中的每个字段都将成为Java Map中的键,值对。

这是一个使用Jackson ObjectMapper从JSON字符串读取Java Map的示例:

//JSON字符串-->Map
public class JsonToJava7 {

    public static void main(String[] args) throws IOException {
        String json = "{\"name\":\"swx\",\"age\":18,\"skillsList\":[\"java\",\"python\",\"php\"]}";
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> objectMap = objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {
        });
        //{name=swx, age=18, skillsList=[java, python, php]}
        System.out.println(objectMap);
    }
}

4.2、Java对象–>JSON

Jackson ObjectMapper也可以用于从对象生成JSON。 可以使用以下方法之一进行操作:

  • writeValue()
  • writeValueAsString()
  • writeValueAsBytes()

重点使用api:objectMapper.writeValueAsString(person);

//java对象转换为json格式
public class JavaToJson {
    public static void main(String[] args) throws JsonProcessingException {
        Person person = new Person();
        person.setName("swx");
        person.setAge(18);
        person.setSkillsList(Arrays.asList("java","python","php"));
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(person);
        //{"name":"swx","age":18,"skillsList":["java","python","php"]}
        System.out.println(json);
    }

}

4.3、Jackson 忽略字段

如果在进行 JSON 转 Java 对象时,JSON 中出现了 Java 类中不存在的属性,那么在转换时会遇到 com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException 异常。

使用 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) 可以忽略不存在的属性。

//Jackson 忽略字段
public class JsonToJava8 {

    public static void main(String[] args) throws IOException {
        String json = "{\"yyy\":\"xxx\",\"name\":\"swx\",\"age\":18,\"skillsList\":[\"java\",\"python\",\"php\"]}";
        ObjectMapper objectMapper = new ObjectMapper();
        //忽略字段设置
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        Person person = objectMapper.readValue(json, Person.class);
        //{name=swx, age=18, skillsList=[java, python, php]}
        System.out.println(person);
    }
}

4.4、Jackson 日期格式化

通过在字段上使用注解 @JsonFormat 来自定义时间格式。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
    private Integer id;
    @JsonFormat(pattern = "yyyy年MM月dd日 HH时mm分ss秒",timezone = "Asia/Shanghai")
    private Date date;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "Asia/Shanghai")
    private LocalDateTime localDateTime;
}

提示

如果运行后报错:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 
			Java 8 date/time type `java.time.LocalDateTime` not supported by default: 
				add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" 
          to enable handling (through reference chain: com.wdbyte.jackson.Order["updateTime"])

这里我们需要添加相应的数据绑定支持包。

添加依赖:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.13.3</version>
</dependency>

然后在定义 ObjectMapper 时通过 findAndRegisterModules() 方法来注册依赖。

//Jackson 日期格式化
public class JsonToJava9 {

    public static void main(String[] args) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
        Order order = new Order();
        order.setId(1);
        order.setDate(new Date());
        order.setLocalDateTime(LocalDateTime.now());
        //将java转换成json字符串
        String json = objectMapper.writeValueAsString(order);
        //{"id":1,"date":"2023年07月28日 15时14分01秒","localDateTime":"2023-07-28 15:14:01"}
        System.out.println(json);
        //将json字符串转换成java对象
        Order orderObject = objectMapper.readValue(json, Order.class);
        //Order(id=1, date=Fri Jul 28 15:15:59 CST 2023, localDateTime=2023-07-28T15:15:59)
        System.out.println(orderObject);
    }
}

4.5、Jackson 常用注解

@JsonIgnore

使用 @JsonIgnore 可以忽略某个 Java 对象中的属性,它将不参与 JSON 的序列化与反序列化。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Cat {
    private String name;
    @JsonIgnore
    private Integer age;
}
// @JsonIgnore
public class JsonToJava10 {

    public static void main(String[] args) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        Cat tom = new Cat("tom", 18);
        String json = objectMapper.writeValueAsString(tom);
        //因为对象属性age设置了被忽略:{"name":"tom"}
        System.out.println(json);
    }
}
@JsonGetter

使用 @JsonGetter 可以在对 Java 对象进行 JSON 序列化时自定义属性名称。

import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;

/**
 * @author https://www.wdbyte.com
 */
@Data
public class Cat {

    private String name;

    private Integer age;

    @JsonGetter(value = "catName")
    public String getName() {
        return name;
    }
}
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

/**
 * @author https://www.wdbyte.com
 */
class CatTest {

    ObjectMapper objectMapper = new ObjectMapper();

    @Test
    void testPojoToJson2() throws JsonProcessingException {
        Cat cat = new Cat();
        cat.setName("Tom");
        cat.setAge(2);
        String json = objectMapper.writeValueAsString(cat);
        System.out.println(json);
        Assertions.assertEquals(json, "{\"age\":2,\"catName\":\"Tom\"}");
    }
}

输出结果,name 已经设置成了 catName

{"age":2,"catName":"Tom"}
@JsonSetter

使用 @JsonSetter 可以在对 JSON 进行反序列化时设置 JSON 中的 key 与 Java 属性的映射关系。

package com.wdbyte.jackson;

import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonSetter;
import lombok.Data;

/**
 * @author https://www.wdbyte.com
 * @date 2022/07/17
 */
@Data
public class Cat {
    @JsonSetter(value = "catName")
    private String name;

    private Integer age;

    @JsonGetter(value = "catName")
    public String getName() {
        return name;
    }
}
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

/**
 * @author https://www.wdbyte.com
 */
class CatTest {

    ObjectMapper objectMapper = new ObjectMapper();

    @Test
    void testPojoToJson2() throws JsonProcessingException {
        String json = "{\"age\":2,\"catName\":\"Tom\"}";
        Cat cat = objectMapper.readValue(json, Cat.class);
        System.out.println(cat.toString());
        Assertions.assertEquals(cat.getName(), "Tom");
    }
}
Cat(name=Tom, age=2)

Jackson 总结

  • Jackson 是 Java 中比较流量的 JSON 处理库之一,它是 Spring 的默认 JSON 工具。
  • Jackson 主要有三个模块组成,Streaming API 、Annotations 和 Data Binding 。
  • Jackson 中的 ObjectMapper 类十分强大,可以进行 JSON 相关处理,同时可以结合注释以及配置进行自定义转换逻辑。
  • Jackson 扩展性很好,如 CSV、XML、YAML 格式处理都对 Jackson 有相应的适配等。
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

six-key

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值