傑克遜構造函數檢測器指南
一、簡介
使用 Jackson 的重要方面之一是了解它如何將 JSON 資料映射到 Java 對象,這通常涉及使用建構函數。此外, ConstructorDetector是 Jackson 中的關鍵元件,它影響反序列化過程中如何選擇建構函式。
在本教程中,我們將詳細探討ConstructorDetector ,說明其目的、配置和用法。
ConstructorDetector :概述
ConstructorDetector是 Jackson 資料綁定模組中的一項功能,可協助確定在反序列化期間考慮建立物件的類別的哪些建構子。 Jackson 使用建構函式來實例化物件並使用 JSON 資料填入其欄位。
ConstructorDetector允許我們自訂和控制 Jackson 應使用哪些建構函數,從而在反序列化過程中提供更大的靈活性。
3. 配置ConstructorDetector
Jackson 提供了幾種預先定義的ConstructorDetector配置,包括USE_PROPERTIES_BASED 、 USE_DELEGATING 、 EXPLICIT_ONLY和DEFAULT 。
3.1. USE_PROPERTIES_BASED
當我們的類別具有與 JSON 屬性相符的建構子時,此配置非常有用。讓我們舉一個簡單的實際例子:
public class User {
private String firstName;
private String lastName;
private int age;
public User(){
}
public User(String firstName, String lastName, int age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
}
在此場景中, User類別具有屬性firstName 、 lastName和age 。 Jackson 會在User中尋找具有與這些屬性相符的參數的建構函數,它在提供的User(String firstName, String lastName, int age)建構子中找到該建構子。
現在,當使用 Jackson 和ConstructorDetector.USE_PROPERTIES_BASED將 JSON 反序列化為 Java 物件時,Jackson 將利用與 JSON 物件中的屬性最匹配的建構子:
@Test
public void givenUserJson_whenUsingPropertiesBased_thenCorrect() throws Exception {
String json = "{\"firstName\": \"John\", \"lastName\": \"Doe\", \"age\": 25}";
ObjectMapper mapper = JsonMapper.builder()
.constructorDetector(ConstructorDetector.USE_PROPERTIES_BASED)
.build();
User user = mapper.readValue(json, User.class);
assertEquals("John", user.getFirstName());
assertEquals(25, user.getAge());
}
這裡,名為json的字串表示一個具有屬性firstName 、 lastName和age的JSON對象,這些屬性對應於User類別的建構子參數。使用mapper.Jackson will use the readValue(json, User.class) method to利用參數與 JSON 屬性相符的建構子。
如果 JSON 包含其他類別中不存在的字段,Jackson 將忽略這些字段而不會引發錯誤。例如:
String json = "{\"firstName\": \"John\", \"lastName\": \"Doe\", \"age\": 25, \"extraField\": \"extraValue\"}";
User user = mapper.readValue(json, User.class);
在這種情況下, extraField將被忽略。但是,如果建構函數參數與 JSON 屬性不完全匹配,Jackson 可能無法找到合適的建構子並引發錯誤。
3.2. USE_DELEGATING
USE_DELEGATING c允許 Jackson 將物件建立委託給單一參數建構函數。當 JSON 資料結構與單一參數的結構一致時,這會很有用,從而可以建立簡潔的物件。
考慮一個用例,我們有一個類別StringWrapper包裝單一字串值:
public class StringWrapper {
private String value;
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public StringWrapper(@JsonProperty("value") String value) {
this.value = value;
}
@JsonProperty("value")
public String getValue() {
return value;
}
}
StringWrapper類別有一個用@JsonCreator和@JsonProperty註解的單一參數建構函數,指示 Jackson 應該使用委託來建立物件。
讓我們使用 Jackson 和ConstructorDetector.USE_DELEGATING將 JSON 反序列化為 Java 物件:
@Test
public void givenStringJson_whenUsingDelegating_thenCorrect() throws Exception {
String json = "\"Hello, world!\"";
ObjectMapper mapper = JsonMapper.builder()
.constructorDetector(ConstructorDetector.USE_DELEGATING)
.build();
StringWrapper wrapper = mapper.readValue(json, StringWrapper.class);
assertEquals("Hello, world!", wrapper.getValue());
}
在這裡,我們反序列化一個 JSON 字串值“ Hello, world! ” 使用 Jackson 和ConstructorDetector.USE_DELEGATING到StringWrapper物件。 Jackson 利用StringWrapper的單一參數建構函數,正確地映射 JSON 字串值。
如果 JSON 結構與單一參數建構函數不一致,Jackson 將拋出錯誤。例如:
String json = "{\"value\": \"Hello, world!\", \"extraField\": \"extraValue\"}";
StringWrapper wrapper = mapper.readValue(json, StringWrapper.class);
在這種情況下,附加欄位extraField會導致錯誤,因為建構子需要單一字串值,而不是 JSON 物件。
3.3. EXPLICIT_ONLY
此配置可確保僅使用明確註解的建構函式。此外,它還提供對建構函式選擇的嚴格控制,允許開發人員指定 Jackson 在反序列化期間應考慮哪些建構函式。
考慮一個場景,其中Product類別代表具有name和price產品:
public class Product {
private String value;
private double price;
@JsonCreator
public Product(@JsonProperty("value") String value, @JsonProperty("price") double price) {
this.value = value;
this.price = price;
}
public String getName() {
return value;
}
public double getPrice() {
return price;
}
}
此類別有一個以@JsonCreator註解的建構函數,指示 Jackson 在反序列化期間應使用明確的基於建構函數的實例化。
我們來看看反序列化過程:
@Test
public void givenProductJson_whenUsingExplicitOnly_thenCorrect() throws Exception {
String json = "{\"value\": \"Laptop\", \"price\": 999.99}";
ObjectMapper mapper = JsonMapper.builder()
.constructorDetector(ConstructorDetector.EXPLICIT_ONLY)
.build();
Product product = mapper.readValue(json, Product.class);
assertEquals("Laptop", product.getName());
assertEquals(999.99, product.getPrice(), 0.001);
}
在此測試方法中,我們利用ConstructorDetector.EXPLICIT_ONLY配置將表示產品的 JSON 物件反序列化為Product物件。僅考慮Product類別的帶註釋的建構函數。
如果 JSON 物件具有建構函數中不存在的其他字段或缺少必需字段,Jackson 將引發錯誤。例如:
String json = "{\"value\": \"Laptop\"}";
Product product = mapper.readValue(json, Product.class);
這將導致錯誤,因為缺少price欄位。
String json = "{\"value\": \"Laptop\", \"price\": 999.99, \"extraField\": \"extraValue\"}";
Product product = mapper.readValue(json, Product.class);
由於意外字段extraField ,這也會導致錯誤。
3.4. DEFAULT
DEFAULT配置透過考慮建構函式選擇的各種策略提供了平衡的方法。這種類型的配置旨在選擇與 JSON 結構一致的建構函數,同時考慮自訂註解和其他配置選項。
考慮一個場景,其中類別Address表示郵寄地址:
public class Address {
private String street;
private String city;
public Address(){
}
public Address(String street, String city) {
this.street = street;
this.city = city;
}
public String getStreet() {
return street;
}
public String getCity() {
return city;
}
}
Address類別有一個建構函數,其參數與 JSON 屬性street和city相符。
讓我們使用 Jackson 和ConstructorDetector.DEFAULT將 JSON 反序列化為 Java 物件:
@Test
public void givenAddressJson_whenUsingDefault_thenCorrect() throws Exception {
String json = "{\"street\": \"123 Main St\", \"city\": \"Springfield\"}";
ObjectMapper mapper = JsonMapper.builder()
.constructorDetector(ConstructorDetector.DEFAULT)
.build();
Address address = mapper.readValue(json, Address.class);
assertEquals("123 Main St", address.getStreet());
assertEquals("Springfield", address.getCity());
}
Jackson 使用其預設啟發式方法來選擇與 JSON 結構相符的建構函數,確保從 JSON 資料準確地實例化物件。
如果 JSON 結構更複雜或包含不直接匹配任何建構函數的巢狀對象,Jackson 可能找不到合適的建構子並引發錯誤。例如:
String json = "{\"street\": \"123 Main St\", \"city\": \"Springfield\", \"extraField\": \"extraValue\"}";
Address address = mapper.readValue(json, Address.class);
在這種情況下,如果預設配置無法處理, extraField可能會導致錯誤。
4。
總之,了解 Jackson 中ConstructorDetector的用途和配置對於反序列化期間將 JSON 資料有效地映射到 Java 物件至關重要。
與往常一樣,本文的完整程式碼範例可以在 GitHub 上找到。