logo头像

From zero to HERO

JSON类库Jackson注解一览(2)

前言

今天我们接着上一篇文章梳理Jackson的注解。

Jackson注解一览

@JsonFormat

用于序列化和反序列化中特定格式的数据。虽然我们经常使用它来格式化时间,但是它不单单能格式化时间。

格式化时间

这种比较常用,主要用于格式化旧时间API:

@Data
public class JsonFormatUser {

    @JsonFormat(shape = JsonFormat.Shape.NUMBER)
    private Date number;
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date yyyymmdd;
    @JsonFormat(locale = "zh_CN")
    private Date cnDate;

}

三种shape分别输出时间戳,根据时区和既定格式格式化、本地化:

{
  "number" : 1626706386340,
  "yyyymmdd" : "2021-07-19 22:53:06",
  "cnDate" : "2021-07-19T14:53:06.340+00:00"
}

说实话,现在都使用新的时间API,这个注解并不推荐使用。

注意:格式化时间需要带时区。

格式化枚举

public enum GenderEnum {

    /**
     * Female gender.
     */
    FEMALE("0","女"),
    /**
     * Male gender.
     */
    MALE("1","男"),
    /**
     * Unknown gender.
     */
    @JsonEnumDefaultValue
    UNKNOWN("-1","未知");

    private final String value;
    private final String description;

    GenderEnum(String value, String description) {
        this.value = value;
        this.description = description;
    }

    public String getValue() {
        return value;
    }

    public String getDescription() {
        return description;
    }

}

上面这种枚举类只能格式化成枚举名称,很多时候我们期望能够获取键值对的枚举格式,例如GenderEnum.FEMALE:

{"value":"0","description":"女"}

我们只需要使用@JsonFormatshape特性:

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum GenderEnum {
// 省略
}

@JsonGetter和@JsonGetter

json序列化和反序列化时指定属性的Getter和Setter方法。特别针对有些不正规的方法,同时还可以指定别名,例子:

public class GetterAndSetter {
    private String name;

    @JsonGetter("n")
    public String name(){
        return this.name;
    }

    @JsonSetter("name")
    public void name(String name){
        this.name= name;
    }
}

断言测试:

GetterAndSetter getterAndSetter = new GetterAndSetter();
getterAndSetter.name("felord.cn");

String s = objectMapper.writeValueAsString(getterAndSetter);
Object n = JsonPath.parse(s)
        .read(JsonPath.compile("$.n"));
Assertions.assertEquals("felord.cn",n);

String json = "{\"name\":\"felord.cn\"}";

GetterAndSetter getAndSet = objectMapper.readValue(json, GetterAndSetter.class);

Assertions.assertEquals("felord.cn",getAndSet.name());

大部分情况下这两个注解比JsonProperty注解更加通用。

@JsonIdentityInfo

这个作用于类或属性上,被用来在序列化/反序列化时为该对象或字段添加一个对象识别码,比如@id或者Class对象名,主要解决字段循环嵌套的问题,例如数据库中的多对多关系,Bean嵌套依赖。开发ORM的相关功能时会用到。目前胖哥还没遇到这种场景。

扩展@JsonIdentityReference 具有类似的功能,强调了使用id作为标识。

@JsonIgnore

这个也是常用的一个注解。在序列化/反序列化时忽略被该注解标记的属性。这个注解和前面介绍的@JsonFilter提供的功能差不多。不过该注解是静态标记。

注意JsonProperty注解的access也可以实现该注解的功能,不建议两个注解混用,这样可能发生冲突。

@JsonIgnoreProperties

这个也经常使用。在序列化/反序列化时忽略多个属性,标记在类上。例如忽略internalIdsecretKey属性:

@JsonIgnoreProperties({ "internalId", "secretKey" }

干脆点,如果有些属性我们不太确定我们也可以通过该注解过滤掉,避免未知属性异常:

@JsonIgnoreProperties(ignoreUnknown=true)

@JsonIgnoreType

序列化/反序列化时如果我们希望忽略掉某种特定类型可以借助于该注解:

     @JsonIgnoreType    class Credentials {       public String password;    }      class Settings {       public int userId;       public String name;       public Credentials pwd;    }

Settings进行序列化和反序列化时Credentials将会被忽略掉。主要用来对一些数据敏感的对象进行忽略,比如用户的凭据。

@JsonInclude

用于指示属性何时可以被序列化,我们可以把该注解标记到属性字段上,也可以通过setSerializationInclusion 方法统一设置。常用的JsonInclude.Include.NON_NULL可以过滤空值:

Player player = new Player();player.setId(1);player.setName(null);

对应:

{"id":1}

其它策略参见JsonInclude.Include

扩展:使用CUSTOM策略时可以实现自定义测过滤方法。

@JsonIncludeProperties

这个注解机制有点类似@JsonIgnoreProperties,只不过它的功能和@JsonIgnoreProperties相反。如果一个类标记了这个注解:

@JsonIncludeProperties({ "internalId", "secretKey" })

除了internalIdsecretKey属性,其它属性都不参与序列化和反序列化。

@JsonProperty

@JsonProperty也是常用注解。用来标记属性或者属性的getter和setter方法上,用于指定属性的json名称,类似@JsonAlias的效果,同时配合其Access枚举可以实现那些属性可以序列化,那些属性可以反序列化(类似忽略的效果)。

@Datapublic class MapUser {    @JsonProperty(value = "myname")    private String name;    @JsonProperty(value = "a")    private Integer age;}// {"myname":"felord.cn","a":22,"}

小结

本篇接着上一篇梳理了一部分Jackson注解的用法和场景,希望能够帮助你日常的开发。还有一部分基于篇幅的原因会在下一篇梳理完毕,还请多多关注和支持。

评论系统未开启,无法评论!