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);
相关推荐
qq_三哥啊2 小时前
【IDEA】设置Debug调试时调试器不进入特定类(Spring框架、Mybatis框架)
spring·intellij-idea·mybatis
别惹CC3 小时前
Spring AI 进阶之路01:三步将 AI 整合进 Spring Boot
人工智能·spring boot·spring
寒士obj3 小时前
Spring事物
java·spring
IT毕设实战小研11 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
甄超锋13 小时前
Java ArrayList的介绍及用法
java·windows·spring boot·python·spring·spring cloud·tomcat
Java小白程序员16 小时前
Spring Framework:Java 开发的基石与 Spring 生态的起点
java·数据库·spring
甄超锋17 小时前
Java Maven更换国内源
java·开发语言·spring boot·spring·spring cloud·tomcat·maven
还是鼠鼠18 小时前
tlias智能学习辅助系统--Maven 高级-私服介绍与资源上传下载
java·spring boot·后端·spring·maven
还是大剑师兰特19 小时前
Spring面试题及详细答案 125道(1-15) -- 核心概念与基础1
spring·大剑师·spring面试题·spring教程
python_13621 小时前
web请求和响应
java·spring·github