自定義 Jackson ObjectMapper-Spring Boot教程深入淺出系列


其他教程

初識 Spring Boot-Spring Boot教程深入淺出系列
Spring Boot 配置-Spring Boot教程深入淺出系列
Spring Boot Actuator 介紹-Spring Boot教程深入淺出系列

spring cloud 入門教程

1. 概述

 

當使用 JSON 格式時,Spring Boot 將使用一個ObjectMapper實例來序列化響應和反序列化請求。在本教程中,我們將了解配置序列化和反序列化選項的最常見方法。

 

2. 默認配置

 

默認情況下,Spring Boot 配置將:

  • 禁用MapperFeature.DEFAULT_VIEW_INCLUSION
  • 禁用反序列化Feature.FAIL_ON_UNKNOWN_PROPERTIES
  • 禁用SerializationFeature.WRITE_DATES_AS_TIMESTAMPS

讓我們從一個簡單的例子開始:

  • 客戶端將向我們的/coffee?name=Lavazza發送 GET 請求
  • 控制器將返回一個新的Coffee對象
  • Spring 將使用ObjectMapper將我們的 POJO 序列化為 JSON

我們將使用StringLocalDateTime對象舉例說明自定義選項

 
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" }

我們希望排除值並使用自定義日期格式 (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 。 最終結果將是:

{
  "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 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
  • 禁用反序列化Feature.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()); }

5. 測試配置

 

為了測試我們的配置,我們將使用TestRestTemplate並將對象序列化為String通過這種方式,我們可以驗證我們的Coffee對象是在沒有值和自定義日期格式的情況下序列化的

@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 + "\"}"); }

6. 結論

 

在本教程中,我們了解了使用 Spring Boot 時配置 JSON 序列化選項的幾種方法。

我們看到了兩種不同的方法:配置默認選項或覆蓋默認配置。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM