1. 概述
在本教程中,我們將學習如何在 Jackson 中使用 @JsonFormat。
@JsonFormat 是 Jackson 中的一個註解,它允許我們配置屬性值的序列化或反序列化方式。例如,我們可以指定如何根據 SimpleDateFormat 格式來格式化 Date 和 Calendar 值。
2. Maven 依賴
<em @JsonFormat</em> 在 jackson-databind 包中定義,因此我們需要以下 Maven 依賴:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.2</version>
</dependency>3. Getting Started
This section provides a basic introduction to the system. It covers the initial setup, installation process, and a simple example to get you started.
3.1 Installation
- Download the latest version of the software from our website: https://www.example.com/download
- Extract the downloaded archive to a directory of your choice.
- Run the
setup.exefile to begin the installation process. Follow the on-screen instructions.
3.2 First Steps
- Launch the application from the Start Menu or Desktop shortcut.
- The first time you run the application, you will be prompted to create a new project.
- Choose a project name and location.
3.3 Simple Example
# This is a simple Python script to print "Hello, World!"
print("Hello, World!")
3.1. 使用默認格式
我們將首先演示使用 <em @JsonFormat</em> 註解的概念,以一個表示用户的類為例。
由於我們希望詳細解釋註解的細節,因此 User 對象將在請求時創建(不存儲或從數據庫加載),並將其序列化為 JSON:
public class User {
private String firstName;
private String lastName;
private Date createdDate = new Date();
// standard constructor, setters and getters
}
構建並運行此代碼示例將返回以下輸出:
{"firstName":"John","lastName":"Smith","createdDate":1482047026009}如我們所見,createdDate 字段顯示為自紀元以來的毫秒數,這是 Date 字段的默認格式。
3.2. 使用 Getter 註解
我們將使用 <em @JsonFormat</em> 來指定序列化 <em createdDate</em> 字段的格式。
讓我們看一下 User 類針對此更改所做的更新。 我們通過註解 <em createdDate</em> 字段,如所示,來指定日期格式。
用於 <em pattern</em> 參數的數據格式由 <em <a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/text/SimpleDateFormat.html">SimpleDateFormat</a></em> 規範。
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd@HH:mm:ss.SSSZ")
private Date createdDate;實施此更改後,我們重新構建項目並運行它。
以下是輸出:
{"firstName":"John","lastName":"Smith","createdDate":"2016-12-18@07:53:34.740+0000"}我們使用指定的 SimpleDateFormat 格式來格式化 createdDate 字段,使用了 @JsonFormat 註解。
上述示例演示了在字段上使用註解的方法。我們也可以將其用於 getter 方法(屬性)。
例如,我們可能有一個在調用時計算的屬性。在這種情況下,我們可以將註解用於該 getter 方法。
請注意,我們還更改了模式以僅返回瞬時的時間部分:
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
public Date getCurrentDate() {
return new Date();
}以下是輸出結果:
{ ... , "currentDate":"2016-12-18", ...}3.3. 指定區域設置
除了指定日期格式,我們還可以指定序列化的區域設置。
未指定此參數將導致使用默認區域設置進行序列化:
@JsonFormat(
shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd@HH:mm:ss.SSSZ", locale = "en_GB")
public Date getCurrentDate() {
return new Date();
}3.4. 指定形狀
使用 @JsonFormat,並將 shape 設置為 JsonFormat.Shape.NUMBER,將產生對 Date 類型默認輸出——自紀元以來(以毫秒為單位)的數值。
pattern 參數在此情況下不適用且將被忽略:
@JsonFormat(shape = JsonFormat.Shape.NUMBER)
public Date getDateNum() {
return new Date();
}讓我們來看一下輸出:
{ ..., "dateNum":1482054723876 }4. 不區分大小寫的反序列化
有時,我們從各種來源接收到 JSON 文檔,這些文檔在屬性名稱的大小寫規則上不一致。例如,一個 JSON 文檔包含 “firstname”: “John”,而其他文檔可能包含 “firstName”: “John” 或 “FIRSTNAME”: “John”。
默認的反序列化器無法自動識別不同大小寫字母的屬性名稱。讓我們通過一個例子快速理解這個問題。
首先,假設我們有以下 JSON 文檔作為輸入:
static final String JSON_STRING = "{\"FIRSTNAME\":\"John\",\"lastname\":\"Smith\",\"cReAtEdDaTe\":\"2016-12-18@07:53:34.740+0000\"}";如我們所見,三個屬性“FIRSTNAME”、“lastname”和“cReAtEdDaTe”完全遵循不同的大小寫規則。現在,如果我們將此JSON文檔反序列化為User對象,將會拋出UnrecognizedPropertyException:
assertThatThrownBy(() -> new ObjectMapper().readValue(JSON_STRING, User.class)).isInstanceOf(UnrecognizedPropertyException.class);如上測試所示,我們使用了 Assertj 的異常斷言來驗證預期異常是否被拋出。
為了解決此類問題,我們必須使我們的反序列器執行不區分大小寫的反序列化。
因此,接下來我們來探討如何使用 @JsonFormat 註解來實現這一點。
@JsonFormat 註解允許我們通過 with 屬性設置一組 JsonFormat.Feature 值:@JsonFormat(with = JsonFormat.Feature … ).
JsonFormat.Feature 是一種枚舉。它預定義了一組選項,用於指定屬性序列化或反序列化行為。
ACCEPT_CASE_INSENSITIVE_PROPERTIES 特性告訴反序列器匹配屬性名稱時不區分大小寫。要使用此特性,我們可以將其包含在類級別的 @JsonFormat 註解中。
接下來,讓我們創建一個 UserIgnoreCase 類,其中包含此註解和特性:
@JsonFormat(with = JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
class UserIgnoreCase {
private String firstName;
private String lastName;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd@HH:mm:ss.SSSZ")
private Date createdDate;
// the rest is the same as the User class
...
};
現在,如果我們將我們的 JSON 輸入反序列化到 UserIgnoreCase,它將按預期工作:
UserIgnoreCase result = new ObjectMapper().readValue(JSON_STRING, UserIgnoreCase.class);
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSzz");
Date expectedDate = fmt.parse("2016-12-18T07:53:34.740+0000");
assertThat(result)
.isNotNull()
.returns("John", from(UserIgnoreCase::getFirstName))
.returns("Smith", from(UserIgnoreCase::getLastName))
.returns(expectedDate, from(UserIgnoreCase::getCreatedDate));值得一提的是,我們使用了 Assertj 的 returns() 和 from() 方法來在一個單一斷言中驗證多個屬性。這非常方便,並且使代碼更易於閲讀。
5. 結論
總而言之,我們使用 @JsonFormat 來控制 Date 和 Calendar 類型的數據輸出格式。