Java 操作 JSON 数据(4)--Jackson 操作 JSON 数据

Jackson 是 SpringBoot 默认使用的 JSON 处理库,它可以轻松的将 Java 对象转换成 JSON 对象,同样也可以将 JSON 转换成 Java对 象。本文介绍下 Jackson 的基本使用方法,包括序列化和反序列化;文中所使用到的软件版本:Java 1.8.0_321、Jackson 2.13.3。

1、简介

Jackson 被称为 Java JSON 库 或 Java 最佳 JSON 解析器,或者干脆写成 “JSON for Java”。更重要的是,Jackson 是一套 Java 平台的 数据处理(不限于JSON) 工具集:包括 一流的 JSON 解析器/JSON 生成器、数据绑定库(POJOs to and from JSON);并且提供了相关模块来支持 Avro, BSON, CBOR, CSV, Smile, Properties, Protobuf, XML or YAML 等数据格式,甚至还支持大数据格式模块的设置。

Jackson 的特点:

高性能且稳定:低内存占用,对大小 JSON 串,大小对象的处理表现均很优秀
流行度高:是很多流行框架的默认选择
容易使用:提供高层次的 API,极大简化了使用
无需创建映射:内置了大量 Java 类型的映射类
灵活:内置大量配置项以满足不同业务需求

2、Jackson 配置

Jackson 框架中包含了大量的配置让我们可以干预 Jackson 处理 JSON 的过程,这样就能满足各种个性要求。

2.1、使用注解

注解 作用域 说明 生效时机
@JsonIgnore
属性或getter/setter方法上 忽略该注解标注的属性 序列化和反序列化时
@JsonIgnoreProperties
类上 和 @JsonIgnore 作用相同;不同之处是 @JsonIgnoreProperties 是类级别的,并且可以同时指定多个属性。 序列化和反序列化时
@JsonIgnoreType
类上 当其他类有该类作为属性时,该属性将被忽略 序列化和反序列化时
@JsonIgnoreType 类上  指定属性对应 JSON 映射的名称  序列化和反序列化时
@JsonPropertyOrder 类上 序列化时指定属性在 JSON 中的次序 序列化时
@JsonInclude 类或属性或getter/setter方法上

指定属性什么情况下会序列化

JsonInclude.Include.ALWAYS 总是写入 JSON,默认
JsonInclude.Include.NON_DEFAULT 属性为默认值不序列化
JsonInclude.Include.NON_NULL 属性为 NULL不序列化
JsonInclude.Include.NON_EMPTY 属性为空("")或者为 NULL 都不序列化

序列化时
@JsonFormat 属性或getter/setter方法上

定义日期类型的属性如何序列化和反序列化

序列化和反序列化时
@JsonSerialize 属性或getter/setter方法上  定义属性序列化的类  序列化时
@JsonDeserialize 属性或getter/setter方法上 定义属性反序列化的类 反序列化时
@JsonGetter getter方法上 标注于 getter 方法上,类似 @JsonProperty,也可以解决 json 键名称和 Java POJO 属性名称不匹配的问题 序列化时
@JsonSetter setter方法上 标注于 setter 方法上,类似 @JsonProperty,也可以解决 json 键名称和 Java POJO 属性名称不匹配的问题 反序列化时

2.2、使用 ObjectMapper 的 setXX 方法

//设置日期格式,作用和 @JsonFormat 类似
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
//反序列化时,实体类中没有对应属性时是否抛出异常
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//指定属性什么情况下会序列化,作用和 @JsonInclude 类似 objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); //字符串如果为 null 则输出 "" objectMapper.setSerializerFactory(objectMapper.getSerializerFactory().withSerializerModifier(new BeanSerializerModifier() { @Override public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) { for (BeanPropertyWriter writer : beanProperties) { Class<?> clazz = writer.getType().getRawClass(); if (CharSequence.class.isAssignableFrom(clazz) || Character.class.isAssignableFrom(clazz)) { writer.assignNullSerializer(new JsonSerializer<Object>() { @Override public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeString(""); } }); } } return beanProperties; } })); ...

3、具体使用

3.1、引入依赖

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

如果使用了 Java8 的时间类型,还需引入:

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

3.2、定义实体类

package com.abc.demo.json;

import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.Data;
import lombok.ToString;

import java.time.LocalDateTime;

@Data
@ToString
public class Student {
    @JsonProperty("studentId")
    private Long id;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    private LocalDateTime createTime;

    private String name;

    @JsonIgnore
    private String homeAddress;
}

3.3、序列化及反序列化

package com.abc.demo.json;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

public class JacksonCase {
    private static final Logger logger = LoggerFactory.getLogger(JacksonCase.class);

    private ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 序列化
     */
    @Test
    public void serialize() throws IOException {
        Student student = new Student();
        student.setId(1L);
        student.setCreateTime(LocalDateTime.now());
        student.setName("小明");
        student.setHomeAddress("江苏");
        logger.info(objectMapper.writeValueAsString(student));

        //使用流式 API 生成 JSON,但只能序列化简单类型的 Java 对象
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        JsonFactory jasonFactory = new JsonFactory();
        JsonGenerator generator = jasonFactory.createGenerator(byteArrayOutputStream);
        //为了支持 Java8 时间类,需做如下设置
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        objectMapper.registerModule(javaTimeModule);
        generator.setCodec(objectMapper);
        
        generator.writeStartObject();
        generator.writeNumberField("id", 1L);
        generator.writeObjectField("createTime", LocalDateTime.now());
        generator.writeStringField("homeAddress", "江苏");
        generator.close();
        logger.info(byteArrayOutputStream.toString());
    }

    /**
     * 反序列化
     */
    @Test
    public void deserialize() throws IOException {
        Student student = new Student();
        student.setId(1L);
        student.setCreateTime(LocalDateTime.now());
        student.setName("小明");
        student.setHomeAddress("江苏");

        Student student2 = new Student();
        student2.setId(2L);
        student2.setCreateTime(LocalDateTime.now());
        student2.setName("小红");
        student2.setHomeAddress("上海");
        List<Student> list = new ArrayList<>();
        list.add(student);
        list.add(student2);

        String json = objectMapper.writeValueAsString(student);
        String json2 = objectMapper.writeValueAsString(list);

        //反序列化为实体对象
        Student student3 = objectMapper.readValue(json, Student.class);
        logger.info(student3.toString());

        //反序列化为集合
        TypeReference<List<Student>> typeReference = new TypeReference<List<Student>>(){};
        List<Student> students = objectMapper.readValue(json2, typeReference);
        logger.info(students.toString());

        //使用树模型 API 解析 JSON
        JsonNode root = objectMapper.readTree(json2);
        JsonNode jsonNode = root.get(0);
        logger.info("第一条数据,{}", jsonNode.toString());
        logger.info("第一条数据,id={}", jsonNode.get("studentId").asLong());
        logger.info("第一条数据,name={}", jsonNode.get("name").asText());
        //...

        //使用流式 API 解析 JSON,使用 nextToken() 不停的往前遍历 JSON 数据,检查令牌类型并读取数据
        JsonFactory jsonFactory = new JsonFactory();
        JsonParser jsonParser = jsonFactory.createParser(json2);
        while (jsonParser.nextToken() != null) {
            logger.info(jsonParser.currentToken().toString());
            String key = jsonParser.getCurrentName();
            if (key != null) {
                jsonParser.nextToken();
                logger.info("key={},value={}", key, jsonParser.getText());
            }
        }
    }
}

 

 

posted @ 2019-12-10 15:39  且行且码  阅读(1286)  评论(0编辑  收藏  举报