Spring Boot – Personaliza el ObjectMapper de Jackson

Al usar el formato JSON, Spring Boot usará una instancia de ObjectMapper para serializar las respuestas y deserializar las requests. En este artículo, veremos las formas más comunes de configurar las opciones de serialización y deserialización.

Veamos la configuración predeterminada. Entonces, por defecto, la configuración de Spring Boot será la siguiente:

  • Deshabilitar MapperFeature.DEFAULT_VIEW_INCLUSION
  • Deshabilite la característica de deserialización. FALLO_EN_PROPIEDADES_DESCONOCIDAS
  • Deshabilite la característica de serialización. ESCRIBIR_FECHAS_AS_TIMESTAMPS

Comencemos con un ejemplo más rápido implementando el mismo

Implementación: 

  • El cliente envía una solicitud GET a nuestro/coffee?name=Lavazza
  • El controlador devolverá un nuevo objeto Café.
  • Spring usará opciones de personalización mediante el uso de objetos String y LocalDateTime

Es el siguiente, por lo que principalmente necesitamos crear una clase llamada Coffee, que es la siguiente:

// Class
public class Coffee {

  // Getters and setters
  private String name;
  private String brand;
  private LocalDateTime date;
}
  • Ahora también definiremos un controlador REST simple para demostrar la serialización:
@GetMapping ("/coffee")

public Coffee getCoffee(
  @RequestParam(required =  false) String brand,
  @RequiredParam(required = false) String name) {

  return new Coffee()
         .setBrand(brand)
         .setDate(FIXED_DATE)
         .setName(name);
}
  • Por defecto, la respuesta al llamar a GET http://localhost:8080/coffee? brand =lavazza será la siguiente :
{
  "name": null,
  "brand": Lavazza",
  "date": "2020 - 11 - 16T10: 21: 35.974"
}
  • Ahora nos gustaría excluir valores nulos y tener un formato de fecha personalizado (dd-MM-yyy HH:mm) . La respuesta final será la siguiente:
{
  "brand:" "Lavazza",
  "date": "04-11-20202 10:34"
}
  • Cuando usamos Spring Boot, tenemos la opción de personalizar el ObjectMapper predeterminado o anularlo. Cubriremos ambas opciones en las siguientes secciones.

Ahora pasemos al punto excéntrico del artículo personalizando el asignador de objetos predeterminado. Aquí. discutiremos cómo personalizar el ObjectMapper predeterminado que usa Spring Boot.

Propiedades de la aplicación y módulo Jackson personalizado

La forma más sencilla de configurar el mapeador es a través de las propiedades de la aplicación.  La estructura general de la configuración es la siguiente:

  spring.jackson.<category_name>.<feature_name>=true, false

Como ejemplo, si queremos deshabilitar SerializationFeature. WRITE_DATES_AS_TIMESTAMPS, agregaremos:

spring.jackson.serialization.write-dates-as-timestamps=false

Además de las categorías de características mencionadas, también podemos configurar la inclusión de propiedades:

spring.jackson.default-property-inclusion=always, non_null, non_absent, non_default, non_empty

Configuración de las variables de entorno en el enfoque más simple. La desventaja de este enfoque es que no podemos personalizar las opciones avanzadas, como tener un formato de fecha personalizado para LocalDateTime. En este punto, obtendremos el resultado que se muestra a continuación:

{
  "brand": "Lavazza",
  "date": "2020-11-16T10:35:34.593"
}

Ahora, para lograr nuestro objetivo, registraremos un nuevo JavaTimeModule con nuestro formato de fecha personalizado:

@Configuration
@PropertySource("classpath:coffee.properties")

// Class
public class CoffeeRegisterModuleConfig {

  @Bean

  public Module javaTimeModule() {

    JavaTimeModule module = new JavaTimeModule();
    module.addSerializer(LOCAL_DATETIME_SERIALIZER);

    return module;
  }
}

Jackson2ObjectMapperBuilderPersonalizador

El propósito de esta interfaz funcional es permitirnos crear beans de configuración. Se aplicarán al ObjectMapper predeterminado creado a través de Jackson2ObjectMapperBuilder.

@Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
  return builder ->
         builder.serializationInclusion(JsonInclude.Include.NON_NULL)
         .serializers(LOCAL_DATETIME_SERIALIZER);
}

Los beans de configuración se aplican en un orden específico, que podemos controlar usando las anotaciones @Order. Este enfoque elegante es adecuado si queremos configurar ObjectMapper desde diferentes configuraciones o módulos.

Jackson2ObjectMapperBuilder

Otro enfoque limpio es definir un bean Jackson2ObjectMapperBuilder. En realidad, Spring Boot usa este constructor de manera predeterminada al construir el ObjectMapper y automáticamente recogerá el definido:

@Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
  return new
         Jackson2ObjectMapperBuilder().serializers(LOCAL_DATETIME_SERIALIZER)
         .serializationInclusion(JsonInclude.Include.NON_NULL);
}

Configurará dos opciones por defecto:

  • Deshabilitar MapperFeature.DEFAULT_VIEW_INCLUSION
  • Deshabilitar DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES

Según la documentación de Jackson2ObjectMapperBuilder, también registrará algunos módulos si están presentes en el classpath:

  • jackson-datatype-jdk8: soporte para otros tipos de Java 8 como Opcional
  • jackson-datatype-jsr310: soporte para tipos de API de fecha y hora de Java 8
  • jackson-datatype-joda: soporte para tipos Joda-Time
  • jackson-module-kotlin: soporte para clases de Kotlin y clases de datos

Nota: La ventaja de este enfoque es que Jackson2ObjectMapperBuilder ofrece una manera simple e intuitiva de construir un ObjectMapper.

Simplemente podemos definir un bean con el tipo MappingJackson2HttpMessageConverter, y Spring Boot lo usará automáticamente:

@Bean

// Convertor method
public MappingJackson2HttpMessageConverter() {

  Jackson2ObjectMapperBuilder builder = new
  Jackson2ObjectMapperBuilder().serializers(LOCAL_DATE_SERIALIZER)
  .serializationInclusion(JsonInclude.Include.NON_NULL);

  return new MappingJackson2HttpMessageConverter(builder.build());
}

Nota: asegúrese de consultar nuestro artículo Spring Http Message Converters para obtener más información.

Prueba de la configuración

Por último, para probar nuestra configuración, usaremos TestRestTemplate y serializaremos los objetos como String. De esta forma, podemos validar que nuestro objeto Coffee esté serializado sin valores nulos y con el formato de fecha personalizado:

@Test

public void whenGetCoffee_thenSerializedWithDateAndNonNull() {

  String formattedDate =
    DateTimeFormatter.ofPattern(CoffeeConstants.dateTimeFormat).format(FIXED_DATE);

// Our strings
  String brand = "Lavazza";
  String url = "/coffee?branf=" + brand;
  String response = restTemplate.getForObject(url, String.class);

  assertThat(response).isEqualTo("{"brand\":\"" + brand +
                                "\",\"date\":\"" + formatedDate + "\"}");
}

Conclusión: Echamos un vistazo a varios métodos para configurar las opciones de serialización de JSON al usar Spring Boot. Aquí vimos dos enfoques diferentes: configurar las opciones predeterminadas o anular la configuración predeterminada.

Publicación traducida automáticamente

Artículo escrito por akashpandit1103 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *