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,默认 |
序列化时 |
@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()); } } } }