1. Обзор
При использовании формата JSON Spring Boot будет использовать экземпляр ObjectMapper
для сериализации ответов и десериализации запросов.
В этом руководстве мы рассмотрим наиболее распространенные способы настройки параметров сериализации и десериализации.
Чтобы узнать больше о Джексоне, обязательно ознакомьтесь с нашим руководством по Джексону .
2. Конфигурация по умолчанию
По умолчанию конфигурация Spring Boot отключает следующее:
MapperFeature.DEFAULT_VIEW_INCLUSION
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
Функция сериализации.WRITE_DATES_AS_TIMESTAMPS
Давайте начнем с быстрого примера:
- Клиент отправит запрос 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"
}
Мы хотели бы исключить нулевые
значения и иметь собственный формат даты (дд-мм-гггг ЧЧ:мм). Это наш последний ответ:
{
"brand": "Lavazza",
"date": "04-11-2020 10:34"
}
При использовании Spring Boot у нас есть возможность настроить ObjectMapper
по умолчанию или переопределить его. Мы рассмотрим оба варианта в следующих разделах.
3. Настройка ObjectMapper по умолчанию
В этом разделе мы увидим, как настроить ObjectMapper
по умолчанию , который использует Spring Boot.
3.1. Свойства приложения и пользовательский модуль Джексона
Самый простой способ настроить картограф — через свойства приложения.
Вот общая структура конфигурации:
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 автоматически зарегистрирует любой bean-компонент типа com.fasterxml.jackson.databind.Module
. Вот наш окончательный результат:
{
"brand": "Lavazza",
"date": "16-11-2020 10:43"
}
3.2. Jackson2ObjectMapperBuilderCustomizer
Назначение этого функционального интерфейса — позволить нам создавать компоненты конфигурации.
Они будут применены к ObjectMapper
по умолчанию, созданному с помощью Jackson2ObjectMapperBuilder
:
@Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
return builder -> builder.serializationInclusion(JsonInclude.Include.NON_NULL)
.serializers(LOCAL_DATETIME_SERIALIZER);
}
Компоненты конфигурации применяются в определенном порядке, которым мы можем управлять с помощью аннотации @Order
. Этот элегантный подход подходит, если мы хотим настроить ObjectMapper
из разных конфигураций или модулей.
4. Переопределение конфигурации по умолчанию
Если мы хотим иметь полный контроль над конфигурацией, есть несколько опций, которые отключат автоматическую настройку и позволят применять только нашу пользовательскую конфигурацию.
Давайте внимательно рассмотрим эти варианты.
4.1. ObjectMapper
Самый простой способ переопределить конфигурацию по умолчанию — определить bean-компонент ObjectMapper
и пометить его как @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
Другой чистый подход заключается в определении bean -компонента Jackson2ObjectMapperBuilder
.
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, таких как
необязательный
- jackson-datatype-jsr310: поддержка типов Java 8 Date and Time API
- jackson-datatype-joda: поддержка типов Joda-Time
- jackson-module-kotlin: поддержка классов Kotlin и классов данных
Преимущество этого подхода в том, что Jackson2ObjectMapperBuilder
предлагает простой и интуитивно понятный способ создания ObjectMapper
.
4.3. СопоставлениеJackson2HttpMessageConverter
Мы можем просто определить bean-компонент с типом MappingJackson2HttpMessageConverter
, и 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 сериализован без
нулевых
значений и с пользовательским форматом даты:
@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. Заключение
В этой статье мы рассмотрели несколько методов настройки параметров сериализации JSON при использовании Spring Boot.
Мы видели два разных подхода: настройка параметров по умолчанию или переопределение конфигурации по умолчанию.
Как всегда, полный исходный код статьи доступен на GitHub .