1. 概述
本快速教程將分析沒有獲取器(getters)的實體 marshalling 以及針對 Jackson <em >JsonMappingException</em > 異常的解決方案。
如果您想更深入地瞭解 Jackson 2 可以做什麼的其他酷炫功能,請訪問主 Jackson 教程。
2. 問題
默認情況下,Jackson 2 僅會處理具有以下任何一種屬性的字段:公開的字段,或具有公開的 getter 方法。 如果實體所有字段都設置為私有或包私有,則序列化實體將會失敗:
public class MyDtoNoAccessors {
String stringValue;
int intValue;
boolean booleanValue;
public MyDtoNoAccessors() {
super();
}
// no getters
}@Test(expected = JsonMappingException.class)
public void givenObjectHasNoAccessors_whenSerializing_thenException()
throws JsonParseException, IOException {
String dtoAsString = new ObjectMapper().writeValueAsString(new MyDtoNoAccessors());
assertThat(dtoAsString, notNullValue());
}完整的異常信息是:
com.fasterxml.jackson.databind.JsonMappingException:
No serializer found for class dtos.MyDtoNoAccessors
and no properties discovered to create BeanSerializer
(to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) )3. 解決方案
顯而易見的方法是為字段添加 getter – 如果該實體在我們控制之下。如果情況並非如此,且無法修改實體的源頭 – 則 Jackson 提供了幾個替代方案。
3.1. 全局自動檢測所有可見字段
一種解決此問題的方案是全局配置 ObjectMapper 以檢測所有字段,無論其可見性如何:
objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);這將允許檢測私有和包私有字段,而無需使用 getter 方法,並且序列化將正常工作:
@Test
public void givenObjectHasNoAccessors_whenSerializingWithAllFieldsDetected_thenNoException()
throws JsonParseException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
String dtoAsString = objectMapper.writeValueAsString(new MyDtoNoAccessors());
assertThat(dtoAsString, containsString("intValue"));
assertThat(dtoAsString, containsString("stringValue"));
assertThat(dtoAsString, containsString("booleanValue"));
}3.2. 在類級別檢測所有字段
Jackson 2 還提供了一種選項——而不是全局配置,通過使用 @JsonAutoDetect 註解,控制類級別的字段可見性。
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class MyDtoNoAccessors { ... }通過此註釋,序列化現在應該能夠正確地與此特定類一起工作。
@Test
public void givenObjectHasNoAccessorsButHasVisibleFields_whenSerializing_thenNoException()
throws JsonParseException, IOException {
ObjectMapper objectMapper = new ObjectMapper();
String dtoAsString = objectMapper.writeValueAsString(new MyDtoNoAccessors());
assertThat(dtoAsString, containsString("intValue"));
assertThat(dtoAsString, containsString("stringValue"));
assertThat(dtoAsString, containsString("booleanValue"));
}4. 在 Jackson 中禁用 fail_on_empty_beans
在 Jackson 中,fail_on_empty_beans 功能確定在序列化時,如果對象為空(沒有屬性)是否應拋出異常。 默認情況下,Jackson 在遇到空 Bean 時會拋出異常。
值得注意的是,fail_on_empty_beans 功能默認啓用,因此如果我們想要禁用它,則需要顯式將其設置為 false。 可以通過以下兩種方式來實現,具體取決於我們的特定用例。
4.1. 使用對象映射器配置
我們可以通過直接使用 ObjectMapper 來禁用 fail_on_empty_beans:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);通過以這種方式配置 ObjectMapper,我們告訴 Jackson 在遇到空 Bean 時,不拋出異常。
4.2. 使用 Spring Boot
在 Spring Boot 中,我們可以通過在 application.properties文件中設置以下屬性來全局禁用 fail_on_empty_beans:
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false此屬性可設置為應用程序級別,以控制 Jackson 序列化在整個應用程序中的行為。
5. 結論
本文介紹瞭如何繞過 Jackson 默認字段可見性的方法,通過在 ObjectMapper 全局範圍內或在單個類上配置自定義可見性來實現。Jackson 允許更進一步的自定義,通過提供選項來控制映射器如何看待獲取器、設置器或具有特定可見性的字段。