有道无术,术尚可求,有术无道,止于术。
本系列Jackson 版本 2.17.0
源码地址:https://gitee.com/pearl-organization/study-jackson-demo
文章目录
-
- [1. 前言](#1. 前言)
- [2. 注解大全](#2. 注解大全)
-
- [2.1 @JsonIgnore](#2.1 @JsonIgnore)
- [2.2 @JsonFormat](#2.2 @JsonFormat)
- [2.3 @JsonInclude](#2.3 @JsonInclude)
- [2.4 @JsonProperty](#2.4 @JsonProperty)
- [2.5 @JsonAlias](#2.5 @JsonAlias)
- [2.6 @JsonIgnoreType](#2.6 @JsonIgnoreType)
- [2.7 @JsonIgnoreProperties](#2.7 @JsonIgnoreProperties)
- [2.8 @JsonPropertyOrder](#2.8 @JsonPropertyOrder)
- [2.9 @JsonGetter](#2.9 @JsonGetter)
- [2.10 @JsonSetter](#2.10 @JsonSetter)
1. 前言
在前几篇文档中,我们学习了Jackson
中几个非常重要的类,并实现了一些简单的JSON
数据转换功能。在实际开发中,可能会遇到的一些个性化要求的场景,而不是简单的一些直接转换,例如,对于null
值字段、敏感字段不进行序列化;Long
类型的字段需要序列化为String
类型(不然返回给前端时会丢失精度)...
Jackson
提供了两种方式来满足个性化场景,以定制序列化/反序列化行为:
- 配置注解 :
Jackson
提供了很多注解,用于标识Java Bean
类、方法、构造器、属性 - 配置特性枚举 :
Jackson
提供了很多xxxFeature
枚举类,在读写对象中进行设置
⛹⛹⛹接下来我们了解下Jackson
提供的所有注解,按照它们的使用频率顺序进行讲解。⛹⛹⛹
2. 注解大全
Jackson
中的大部分注解都在jackson-annotations
模块中,位于com.fasterxml.jackson.annotation
包下,在jackson-databind
模块中也提供了一些注解。
2.1 @JsonIgnore
@JsonIgnore
标识序列化/反序列化时是否忽略该字段。
java
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonIgnore {
// 是否忽略,默认true
boolean value() default true;
}
在UserInfo
类的id
属性添加 @JsonIgnore
:
java
public class UserInfo{
@JsonIgnore
// 用户ID
private Long id;
// 省略其他......
}
进行转换:
java
ObjectMapper objectMapper = new ObjectMapper();
// POJO -> JSON
UserInfo user = new UserInfo();
user.setId(1767798780627279333L);
user.setName("老三");
user.setAge(25);
String json = objectMapper.writeValueAsString(user);
System.out.println(json);
// JSON -> POJO
String userJson="{\"id\":1767798780627279873,\"name\":\"坤坤\",\"age\":18,\"org\":null,\"roleList\":null}";
UserInfo readUserByJson = objectMapper.readValue(userJson, UserInfo.class);
System.out.println(readUserByJson);
可以看到id
字段被忽略了:
java
{"name":"老三","age":25,"org":null,"roleList":null}
UserInfo{id=null, name='坤坤', age=18, org=null, roleList=null}
2.2 @JsonFormat
@JsonFormat
标识使用格式模板进行序列化/反序列化。
java
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonFormat {
// 默认的 Locale,java.util.Locale#getDefault()
String DEFAULT_LOCALE = "##default";
// 默认的 时区,来自于 java.util.TimeZone
String DEFAULT_TIMEZONE = "##default";
// 格式模板
String pattern() default "";
// 指定序列化后的类型
Shape shape() default JsonFormat.Shape.ANY;
// Java Locale
String locale() default "##default";
// 时区
String timezone() default "##default";
// 是否启用"宽松"处理
OptBoolean lenient() default OptBoolean.DEFAULT;
// 开启某些特性
Feature[] with() default {};
// 关闭某些特征
Feature[] without() default {};
// 省略其他......
}
在UserInfo
类的birthdayDate
属性添加 @JsonFormat
注解:
java
@JsonFormat(shape= JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private Date birthdayDate;
序列化/反序列化结果:
java
{"id":1767798780627279333,"birthdayDate":"2024-03-21 09:40:33","birthdayLocalDateTime":null,"name":"老三","age":25,"org":null,"roleList":null}
UserInfo{id=1767798780627279333, birthdayDate=Thu Mar 21 09:40:33 CST 2024, birthdayLocalDateTime=null, name='老三', age=25, org=null, roleList=null}
在UserInfo
类的birthdayLocalDateTime
属性添加 @JsonFormat
注解:
java
@JsonFormat(shape= JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private LocalDateTime birthdayLocalDateTime;
这时会报错InvalidDefinitionException
,不支持java.time.LocalDateTime
:
java
Exception in thread "main" 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.pearl.jacksoncore.demo.databind.anno.UserInfo["birthdayLocalDateTime"])
LocalDateTime
是Java 8
中JSR 310
规范下新的日期时间API
,Jackson
核心模块并没有实现支持,需要引入jackson-datatype-jsr310
模块:
xml
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.17.0</version>
</dependency>
并指定序列化/反序列化器:
java
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonFormat(shape= JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
private LocalDateTime birthdayLocalDateTime;
再次运行,结果如下:
java
{"id":1767798780627279333,"birthdayDate":"2024-03-21 09:47:59","birthdayLocalDateTime":"2024-03-21 09:47:59","name":"老三","age":25,"org":null,"roleList":null}
UserInfo{id=1767798780627279333, birthdayDate=Thu Mar 21 09:47:59 CST 2024, birthdayLocalDateTime=2024-03-21T09:47:59, name='老三', age=25, org=null, roleList=null}
2.3 @JsonInclude
@JsonFormat
标识符合指定规格时才进行序列化。
java
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonInclude {
// 规则:
// ALWAYS, 总是序列化
// NON_NULL, 不为NULL才序列化
// NON_ABSENT, NON_NULL的基础上,支持 Optional
// NON_EMPTY, NON_ABSENT的基础上,支持集合、String
// NON_DEFAULT, 不是默认值才序列化
// CUSTOM, 自定义
// USE_DEFAULTS; 默认
// 作用于类、属性
Include value() default JsonInclude.Include.ALWAYS;
// 作用于 Map、AtomicReference等
Include content() default JsonInclude.Include.ALWAYS;
// 自定义规则需要实现的过滤器
Class<?> valueFilter() default Void.class;
// 自定义规则需要实现的过滤器
Class<?> contentFilter() default Void.class;
在UserInfo
类的birthdayDate
属性添加 @JsonFormat
注解,配置规则为NON_NULL
时才进行序列化:
java
@JsonInclude(JsonInclude.Include.NON_NULL)
private String name;
运行结果如下:
java
user.setName(null);
String JsonIncludeJson = objectMapper.writeValueAsString(user);
System.out.println(JsonIncludeJson);
// {"birthdayDate":"2024-03-21 11:00:23","birthdayLocalDateTime":"2024-03-21 11:00:23","age":25,"org":null,"roleList":null}
2.4 @JsonProperty
@JsonProperty
用于在序列化/反序列化时进行重命名。
java
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonProperty {
String USE_DEFAULT_NAME = "";
int INDEX_UNKNOWN = -1;
// 重命名后的属性名称
String value() default "";
String namespace() default "";
boolean required() default false;
// 索引位置
int index() default -1;
String defaultValue() default "";
// 可见性配置 可以控制只在序列化或者只反序列化时生效
Access access() default JsonProperty.Access.AUTO;
public static enum Access {
// 自动确定对此属性的读/或访问权限
AUTO,
// 只读
READ_ONLY,
// 只写
WRITE_ONLY,
// 可读写
READ_WRITE;
}
}
在UserInfo
类的age
属性添加 @JsonProperty
注解:
java
@JsonProperty(value = "userAge")
private Integer age;
序列化后结果:
java
{"userAge":25,"birthdayDate":"2024-03-21 11:43:25","birthdayLocalDateTime":"2024-03-21 11:43:25","org":null,"roleList":null}
2.5 @JsonAlias
@JsonAlias
用于在反序列化时进行重命名。
java
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonAlias {
String[] value() default {};
}
例如JSON
中属性名称为username
,UserInfo
类中的属性名称为name
,则可以使用@JsonAlias
指定反序列化时的别名:
java
@JsonAlias("username")
private String name;
示例如下:
java
String userAliasJson="{\"id\":1767798780627279873,\"username\":\"坤坤\",\"userAge\":18,\"org\":null,\"roleList\":null}";
UserInfo readUserByAliasJson = objectMapper.readValue(userAliasJson, UserInfo.class);
System.out.println(readUserByAliasJson);
// UserInfo{id=null, birthdayDate=null, birthdayLocalDateTime=null, name='坤坤', age=18, org=null, roleList=null}
2.6 @JsonIgnoreType
@JsonIgnoreType
作用于类,当该类作为对象属性在序列化/反序列化时会被忽略。
java
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonIgnoreType {
// 是否忽略,默认 ture
boolean value() default true;
}
例如我们在Org
类中添加该注解:
java
@JsonIgnoreType
public class Org {
// 省略.....
}
执行反序列化:
java
// 6. @JsonIgnoreType
String userJsonIgnoreTypeStr="{\"id\":1767798780627279873,\"username\":\"坤坤\",\"userAge\":18,\"org\":{\"id\":1699967647585800192,\"orgName\":\"阿里巴巴\",\"address\":\"浙江杭州\"},\"roleList\":null}";
UserInfo readUserByJsonIgnoreType = objectMapper.readValue(userJsonIgnoreTypeStr, UserInfo.class);
System.out.println(readUserByJsonIgnoreType);
虽然JSON
内容包含了Org
对象,但是被忽略掉了:
java
UserInfo{id=null, birthdayDate=null, birthdayLocalDateTime=null, name='坤坤', age=18, org=null, roleList=null}
2.7 @JsonIgnoreProperties
@JsonIgnoreProperties
用于在序列化/反序列化 时忽略某个字段属性,比@JsonIgnore
功能更强,可以作用于类,配置多个忽略属性。
java
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonIgnoreProperties {
// 忽略的多个属性名称
String[] value() default {};
// 是否忽略不能识别的属性
boolean ignoreUnknown() default false;
// 是否允许访问属性的Getter方法,即支持Getter进行序列化
boolean allowGetters() default false;
// 是否允许访问属性的Setters方法,即支持Setters进行反序列化
boolean allowSetters() default false;
}
Org
类上标识忽略id
、orgName
属性:
java
@JsonIgnoreProperties({"orgName","id"})
public class Org {
// 省略.....
}
案例演示,当前JSON
包含了id
、orgName
属性:
java
String userIgnorePropertiesStr="{\"id\":1767798780627279873,\"username\":\"坤坤\",\"userAge\":18,\"org\":{\"id\":1699967647585800192,\"orgName\":\"阿里巴巴\",\"address\":\"浙江杭州\"},\"roleList\":null}";
UserInfo readUserByIgnoreProperties = objectMapper.readValue(userIgnorePropertiesStr, UserInfo.class);
System.out.println(readUserByIgnoreProperties);
反序列化时id
、orgName
属性被忽略:
java
UserInfo{id=null, birthdayDate=null, birthdayLocalDateTime=null, name='坤坤', age=18, org=Org{id=null, orgName='null', address='浙江杭州'}, roleList=null}
之外还支持allowGetters
配置可以进行序列化,但反序列化时被忽略(allowSetters
同理):
java
@JsonIgnoreProperties( value = "password",allowGetters = true)
2.8 @JsonPropertyOrder
@JsonPropertyOrder
用于在序列化时进行排序。
java
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonPropertyOrder {
// 指定顺序
String[] value() default {};
// 是否按照字母表排序
boolean alphabetic() default false;
}
示例代码:
java
@JsonPropertyOrder({"org","roleList","birthdayDate","id"})
输出结果:
java
{"org":null,"roleList":null,"birthdayDate":"2024-03-21 14:44:49","birthdayLocalDateTime":"2024-03-21 14:44:49","password":null,"userAge":25}
2.9 @JsonGetter
@JsonGetter
和@JsonProperty
功能类似用于重命名,官方提示使用其替代方案@JsonProperty
。
java
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonGetter {
String value() default "";
}
示例代码:
java
@JsonGetter("userSex")
public String getSex() {
return sex;
}
可以看到在序列化/反序列化 时都会生效,一般使用@JsonProperty
即可:
java
user.setSex("男");
String jsonGettersStr = objectMapper.writeValueAsString(user);
System.out.println(jsonGettersStr);
String jsonGetterStr="{\"userSex\":\"男\",\"id\":1767798780627279873,\"username\":\"坤坤\",\"userAge\":18,\"org\":{\"id\":1699967647585800192,\"orgName\":\"阿里巴巴\",\"address\":\"浙江杭州\"},\"roleList\":null}";
UserInfo readUserByJsonGetter = objectMapper.readValue(jsonGetterStr, UserInfo.class);
System.out.println(readUserByJsonGetter);
2.10 @JsonSetter
@JsonSetter
和@JsonProperty
功能类似用于重命名,官方提示使用其替代方案@JsonProperty
。
java
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonSetter {
String value() default "";
Nulls nulls() default Nulls.DEFAULT;
Nulls contentNulls() default Nulls.DEFAULT;
示例代码:
java
@JsonSetter("mobilePhone")
public void setPhone(String phone) {
this.phone = phone;
}
可以看到在序列化/反序列化时都会生效:
java
user.setPhone("13899996666");
String jsonSettersStr = objectMapper.writeValueAsString(user);
System.out.println(jsonSettersStr);
String jsonSetterStr="{\"mobilePhone\":\"13899996666\",\"userSex\":\"男\",\"id\":1767798780627279873,\"username\":\"坤坤\",\"userAge\":18,\"org\":{\"id\":1699967647585800192,\"orgName\":\"阿里巴巴\",\"address\":\"浙江杭州\"},\"roleList\":null}";
UserInfo readUserByJsoSetter = objectMapper.readValue(jsonSetterStr, UserInfo.class);
System.out.println(readUserByJsoSetter);