Jackson 2.x 系列【5】注解大全篇一

有道无术,术尚可求,有术无道,止于术。

本系列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"])

LocalDateTimeJava 8JSR 310规范下新的日期时间APIJackson核心模块并没有实现支持,需要引入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中属性名称为usernameUserInfo类中的属性名称为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类上标识忽略idorgName属性:

java 复制代码
@JsonIgnoreProperties({"orgName","id"})
public class Org {
	// 省略.....
 }

案例演示,当前JSON包含了idorgName属性:

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);

反序列化时idorgName属性被忽略:

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);
相关推荐
ExiFengs1 小时前
实际项目Java1.8流处理, Optional常见用法
java·开发语言·spring
瓜牛_gn2 小时前
依赖注入注解
java·后端·spring
一元咖啡3 小时前
SpringCloud Gateway转发请求到同一个服务的不同端口
spring·spring cloud·gateway
java亮小白19974 小时前
Spring循环依赖如何解决的?
java·后端·spring
苏-言5 小时前
Spring IOC实战指南:从零到一的构建过程
java·数据库·spring
草莓base5 小时前
【手写一个spring】spring源码的简单实现--容器启动
java·后端·spring
冰帝海岸11 小时前
01-spring security认证笔记
java·笔记·spring
没书读了12 小时前
ssm框架-spring-spring声明式事务
java·数据库·spring
代码小鑫15 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计
真心喜欢你吖15 小时前
SpringBoot与MongoDB深度整合及应用案例
java·spring boot·后端·mongodb·spring