Spring boot:自定義Jackson ObjectMapper
1.概述
當使用JSON格式時,Spring Boot將使用ObjectMapper
實例來序列化響應並反序列化請求。在本教程中,我們將介紹配置序列化和反序列化選項的最常用方法。
要了解有關Jackson的更多信息,請務必查看我們的Jackson教程。
2.默認配置
默認情況下,Spring Boot配置將:
- 停用
MapperFeature.DEFAULT_VIEW_INCLUSION
- 禁用
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
- 禁用
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
讓我們從一個簡單的例子開始:
- 客戶將向我們的
/coffee?name=Lavazza
發送一個GET請求/coffee?name=Lavazza
- 控制器將返回一個新的
Coffee
對象 - Spring將使用
ObjectMapper
將POJO序列化為JSON
我們將使用String
和LocalDateTime
對象舉例說明自定義選項:
public class Coffee {
private String name;
private String brand;
private LocalDateTime date;
//getters and setters
}
我們還將定義一個簡單的REST控制器來演示序列化:
@GetMapping("/coffee")
public Coffee getCoffee(
@RequestParam(required = false) String brand,
@RequestParam(required = false) String name) {
return new Coffee()
.setBrand(brand)
.setDate(FIXED_DATE)
.setName(name);
}
默認情況下,調用GET http://lolcahost:8080/coffee?brand=Lavazza
時的響應將是:
{
"name": null,
"brand": "Lavazza",
"date": "2020-11-16T10:21:35.974"
}
我們想排除null
值,並採用自定義日期格式(dd-MM-yyyy HH:mm)。最終答復將是:
{
"brand": "Lavazza",
"date": "04-11-2020 10:34"
}
使用Spring Boot時,我們可以選擇自定義默認的ObjectMapper
或覆蓋它。我們將在下一部分中介紹這兩個選項。
3.自定義默認的ObjectMapper
在本節中,我們將看到如何自定義Spring Boot使用的默認ObjectMapper
。
3.1。應用程序屬性和自定義Jackson模塊
配置映射器的最簡單方法是通過應用程序屬性。配置的一般結構為:
spring.jackson.<category_name>.<feature_name>=true,false
例如,如果要禁用SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
,我們將添加:
spring.jackson.serialization.write-dates-as-timestamps=false
除了提到的功能類別,我們還可以配置屬性包含:
spring.jackson.default-property-inclusion=always, non_null, non_absent, non_default, non_empty
配置環境變量是最簡單的方法。這種方法的缺點是我們無法自定義高級選項,例如為LocalDateTime
自定義日期格式。至此,我們將獲得結果:
{
"brand": "Lavazza",
"date": "2020-11-16T10:35:34.593"
}
為了實現我們的目標,我們將使用自定義日期格式註冊一個新的JavaTimeModule
:
@Configuration
@PropertySource("classpath:coffee.properties")
public class CoffeeRegisterModuleConfig {
@Bean
public Module javaTimeModule() {
JavaTimeModule module = new JavaTimeModule();
module.addSerializer(LOCAL_DATETIME_SERIALIZER);
return module;
}
}
此外,配置屬性文件coffee.properties
將包含:
spring.jackson.default-property-inclusion=non_null
Spring Boot將自動註冊com.fasterxml.jackson.databind.Module.
類型的任何bean com.fasterxml.jackson.databind.Module.
最終結果將是:
{
"brand": "Lavazza",
"date": "16-11-2020 10:43"
}
3.2。 Jackson2ObjectMapperBuilderCustomizer
該功能接口的目的是允許我們創建配置bean。它們將應用於通過Jackson2ObjectMapperBuilder
創建的默認ObjectMapper
:
@Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
return builder -> builder.serializationInclusion(JsonInclude.Include.NON_NULL)
.serializers(LOCAL_DATETIME_SERIALIZER);
}
配置Bean以特定順序應用,我們可以使用@Order
批註進行控制。如果我們要從不同的配置或模塊配置ObjectMapper
,則這種優雅的方法非常適合。
4.覆蓋默認配置
如果我們想完全控製配置,則有幾個選項將禁用自動配置,並僅允許應用我們的自定義配置。讓我們仔細看看這些選項。
4.1。 ObjectMapper
覆蓋默認配置的最簡單方法是定義一個ObjectMapper
bean並將其標記為@Primary
:
@Bean
@Primary
public ObjectMapper objectMapper() {
JavaTimeModule module = new JavaTimeModule();
module.addSerializer(LOCAL_DATETIME_SERIALIZER);
return new ObjectMapper()
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.registerModule(module);
}
當我們想完全控制序列化過程並且我們不想允許外部配置時,應該使用這種方法。
4.2。 Jackson2ObjectMapperBuilder
另一個乾淨的方法是定義一個Jackson2ObjectMapperBuilder
bean .
實際上,默認情況下,Spring Boot在構建ObjectMapper
時會使用此構建器,並且會自動選擇定義的構建器:
@Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
return new Jackson2ObjectMapperBuilder().serializers(LOCAL_DATETIME_SERIALIZER)
.serializationInclusion(JsonInclude.Include.NON_NULL);
}
默認情況下,它將配置兩個選項:
- 停用
MapperFeature.DEFAULT_VIEW_INCLUSION
- 禁用
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
根據Jackson2ObjectMapperBuilder
文檔,如果類路徑中存在某些模塊,它還將註冊一些模塊:
- jackson-datatype-jdk8:支持其他Java 8類型,例如
Optional
- jackson-datatype-jsr310:支持Java 8日期和時間API類型
- jackson-datatype-joda:支持Joda-Time類型
- jackson-module-kotlin:支持Kotlin類和數據類
這種方法的優點是Jackson2ObjectMapperBuilder
提供了一種簡單直觀的方法來構建ObjectMapper
。
4.3。 MappingJackson2HttpMessageConverter
我們可以定義一個類型為MappingJackson2HttpMessageConverter
的bean,Spring Boot會自動使用它:
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder().serializers(LOCAL_DATETIME_SERIALIZER)
.serializationInclusion(JsonInclude.Include.NON_NULL);
return new MappingJackson2HttpMessageConverter(builder.build());
}
請務必查看我們的Spring Http Message Converters文章以了解更多信息。
5.測試配置
為了測試我們的配置,我們將使用TestRestTemplate
並將對象序列化為String
。這樣,我們可以驗證我們的Coffee
像是否已序列化,沒有null
值並且具有自定義日期格式:
@Test
public void whenGetCoffee_thenSerializedWithDateAndNonNull() {
String formattedDate = DateTimeFormatter.ofPattern(CoffeeConstants.dateTimeFormat).format(FIXED_DATE);
String brand = "Lavazza";
String url = "/coffee?brand=" + brand;
String response = restTemplate.getForObject(url, String.class);
assertThat(response).isEqualTo("{\"brand\":\"" + brand + "\",\"date\":\"" + formattedDate + "\"}");
}
六,結論
在本教程中,我們研究了使用Spring Boot時配置JSON序列化選項的幾種方法。
我們看到了兩種不同的方法:配置默認選項或覆蓋默認配置。