Jackson(3)之常用註解使用

有鹽先生發表於2020-12-06

Jackson根據它的預設方式序列化和反序列化java物件,比如:預設情況下Jackson序列化或反序列化java物件是按物件屬性進行一一匹配、返序列化json串裡不能帶特殊字元等。若根據實際需要,可以靈活的調整Jackson序列化和反序列化的規則。比如:可以設定ObjectMapper屬性(詳細請參考:ObjectMapper配置詳解 ),也可以使用Jackson的註解。常用的註解及詳細的使用方法如下:

(1)@JsonProperty註解

用於物件的屬性,把屬性的名稱在序列化或反序列化時,轉換為另外一個名稱(預設是屬性名稱)。

#示例:UserInfo序列號後birthDate在json串的名稱轉為birth_date
@Data
public class UserInfo implements Serializable {
    @JsonProperty("birth_date")
    private Date birthDate;
    private Integer age;
    private String name;
    private Long id;
}
#下面json串會反序列化失敗,不識別birthDate欄位
{"birthDate":"2020-11-20 10:43:57","id":100,"age":100,"name":"小米"}
#下面json串反序列化成功
{"birth_date":"2020-11-20 10:43:57","id":100,"age":100,"name":"小米"}

(2)@JsonFormat註解

用於屬性或者Getter/Setter方法上,作用是把Date型別序列化成指定格式 和 把指定格式的時間字串反序列化成Date型別。

@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private Date birthDate;

#或者放在Getter/Setter方法上(Getter或Setter上效果一樣,都能控制序列化和反序列化)
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
public Date getBirthDate(){
    return birthDate;
}

注意:@JsonFormat註解和@DateTimeFormat的區別:前端請求Content-Type=application/json的post請求時,@JsonFormat規定接收的時間格式;前端表單提交時,@DateTimeFormat規定接收的時間格式。(詳細請參考:@JsonFormat和@DateTimeFormat本質區別

(3)@JsonPropertyOrder註解

用於類的註解,指定屬性在序列化時json中的順序。(@JsonPropertyOrder註解的alphabetic屬性可用於Json串裡屬性按字母順序排列)

@JsonPropertyOrder({"birthDate", "id","age", "name"}) 
public class UserInfo{
    private Long id;
    private String name;
    private Integer age;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT + 8")
    private Date birthDate;
}
#最終序列化後,json中的順序為@JsonPropertyOrder中指定的順序。
{"birthDate":"2020-11-20 13:14:56","id":1000,"age":10,"name":"小強"}

#序列化後的json串按屬性按字母順序排列
@JsonPropertyOrder(alphabetic = true) 
public class UserInfo{
    private Long id;
    private String name;
    private Integer age;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT + 8")
    private Date birthDate;
}

(4)@JsonCreator註解

用於構造方法,和 @JsonProperty配合使用,適用有引數的構造方法。作用就是指定反序列化時用哪個建構函式。

@Data
public class UserInfo implements Serializable {
    private Long id;
    private String name;
    private Integer age;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT + 8")
    private Date birthDate;
    
    @JsonCreator //json反序列化時呼叫此建構函式
    public UserInfo(@JsonProperty("name") String name) {
        System.out.println("11111111111111111111111111111");
        this.name = name;
    }
    public UserInfo() {
        System.out.println("222222222222222222222222222");
    }
}

public static void main(String[] args) throws Exception {
    ObjectMapper mapper = new ObjectMapper();
	String json = "{"birthDate":"2020-11-20 10:43:57","id":100,"age":100,"name":"小米"}";
	UserInfo userInfo = mapper.readValue(jsonStr, UserInfo.class);
	System.out.println(userInfo);
}
//輸出:反序列化時使用的構造器是帶@JsonCreator的構造器
11111111111111111111111111111
UserInfo(id=100, name=小米, age=100, birthDate=Fri Nov 20 18:43:57 CST 2020)

(5)@JsonIgnore註解

在Java物件序列化為json時 ,有些屬性需要過濾掉不顯示在 json中;反序列化時,即使json串中有屬性的值,也不會注入物件。

@Data
public class UserInfo implements Serializable {
    private Long id;
    @JsonIgnore
    private String name;  //name序列化 和 反序列化時會被忽略掉
    private Integer age;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT + 8")
    private Date birthDate;
}

//測試類
public static void main(String[] args) throws Exception {
	ObjectMapper mapper = new ObjectMapper();
	UserInfo info = new UserInfo();
	info.setAge(100);
	info.setName("直播"); //name序列化會被忽略掉
	info.setId(1000L);
	info.setBirthDate(new Date());
	String json = mapper.writeValueAsString(info);
	System.out.println(json);
	System.out.println("============================");
	//name反序列化會被忽略掉
	String json = "{"birthDate":"2020-11-20 10:43:57","id":100,"age":100,"name":"小米"}";
	UserInfo userInfo = mapper.readValue(json, UserInfo.class);
	System.out.println(userInfo);
}

//輸出:name序列化 和 反序列化時都會被忽略掉
{"id":1000,"age":100,"birthDate":"2020-11-20 11:25:46"}
============================
UserInfo(id=100, name=null, age=100, birthDate=Fri Nov 20 18:43:57 CST 2020)

@JsonIgnoreProperties註解:物件序列化和反序列化時,忽略物件的多個屬性。

@Data
public class PersonInfo implements Serializable {
    private Long Id;
    @JsonIgnoreProperties({"name", "age"})
    private UserInfo userInfo;
}
#@JsonIgnoreProperties過濾多個屬性:userInfo裡的name和age在序列化和反序列化時會被忽略掉

(6)@JsonAnySetter註解

用於屬性或者方法,設定未反序列化的屬性名和值作為鍵值儲存到map; @JsonAnyGetter用於方法 ,獲取所有未序列化的屬性。 所有被Ignore的屬性 和 物件不存在的屬性在反序列號時,都會調一次@JsonAnySetter的方法。

@Data
public class UserInfo implements Serializable {
    private Long id;
    @JsonIgnore
    private String name;
    private Integer age;
    private Map<String, Object> map = new HashMap<>();
    @JsonAnySetter
    public void setOther(String key, Object value) {
        System.out.println("key=" + key + " value=" + value);
        map.put(key, value);
    }
    @JsonAnyGetter
    public Map<String, Object> getOther() {
        return map;
    }
}

//測試方法
public static void main(String[] args) throws Exception {	
	ObjectMapper mapper = new ObjectMapper();
	//反序列化時,因為Java物件name屬性有@JsonIgnore會被忽略,Java物件沒有birthDate會被忽略
	String json = "{"birthDate":"2020-11-20 10:43:57","id":100,"age":100,"name":"小米"}";
	UserInfo userInfo = mapper.readValue(jsonStr, UserInfo.class);
	System.out.println(userInfo);
	System.out.println(userInfo.any());
}

//輸出:所有被Ignore的屬性 和 物件不存在的屬性在反序列號時,都會調一次@JsonAnySetter的方法。
key=birthDate value=2020-11-20 10:43:57
key=name value=小米
UserInfo(id=100, name=null, age=100, map={name=小米, birthDate=2020-11-20 10:43:57})
{name=小米, birthDate=2020-11-20 10:43:57}

(7)@JsonInclude註解

@JsonInclude(JsonInclude.Include.NON_NULL)註解,將該註解放在屬性上,如果該屬性為null則不參與序列化;如果放在類上邊那對這個類的全部屬性起作用。

#示例
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserInfo implements Serializable {
    private Long id;
    private String name;
    private Integer age;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT + 8")
    private Date birthDate;
}
#測試方法
public static void main(String[] args) throws Exception {	
	ObjectMapper mapper = new ObjectMapper();
	UserInfo info = new UserInfo();
	info.setName("訊息");
	info.setBirthDate(new Date());
	System.out.println(mapper.writeValueAsString(info));
}
#輸出:
{"name":"訊息","birthDate":"2020-11-23 02:10:43"}
#UserInfo類去掉@JsonInclude註解後的輸出:json字串裡會有null屬性存在
{"id":null,"name":"訊息","age":null,"birthDate":"2020-11-23 02:17:54"}

@JsonInclude註解除了NON_NULL的使用,還有其很多型別,詳細參考JsonInclude.Include的列舉類。

#(1)@JsonInclude註解的屬性常用的有一下幾種:
    Include.Include.ALWAYS 預設 
    Include.NON_DEFAULT 屬性為預設值不序列化 
    Include.NON_EMPTY 屬性為 空("") 或者為 NULL 都不序列化 
    Include.NON_NULL 屬性為NULL 不序列化

#(2)物件屬性為null不參與序列化,除了使用註解外,也可以直接設定ObjectMapper屬性,如下:
ObjectMapper mapper = new ObjectMapper();
//型別的設定也包含上面四種
mapper.setSerializationInclusion(Include.NON_NULL);

最後,感覺在平時的開發中好多人喜歡用阿里的fastjson官方評價說是最快的json解析框架,但最近幾年經常出高危漏洞,專案也跟著不斷打復補丁,有時候搞得人心惶惶的,特別被動。於是為了不重複造輪子都將Jackson封裝成統一的工具。參考json工具:JsonUtils工具類

       

                                                                                                                          2020年12月06日  晚  於北京記

相關文章