spring-bootspring-batchretrofit2jackson2

How to configure Jackson deserializer for Retrofit2 responses via Jackson2ObjectMapperBuilderCustomizer class?


I am using Retrofit2 to call distant web services in a Spring Batch application, and for deserializing JSON responses I would like to configure a global Jackson deserializer via the Jackson2ObjectMapperBuilderCustomizer class. My configuration is:

I've already tried to define ObjectMapper configuration in a Jackson2ObjectMapperBuilder object and it works, but I still need to specify .addConverter(JacksonConverterFactory.create(<builder>) on each RetrofitBuilder() call:

@Configuration
public class MyRestWSImpl {

    @Bean
    MyRestWS myRestWS (@Value("${url}") String url) {
        return new RetrofitBuilder()
            .url(url)
            .addConverter(JacksonConverterFactory.create(
                new Jackson2ObjectMapperBuilder()
                    .deserializers(new LocalDateTimeDeserializer(MY_DATE_TIME_FORMATTER))
                    .build()
            )
            .client()
            .configure()
            .build()
            .create(MyRestWS.class);
    }
}

I'm searching for a better option. Is there a way in which I can achieve the same result by using the Jackson2ObjectMapperBuilderCustomizer functional interface instead?

I tried to define a bean of type Jackson2ObjectMapperBuilderCustomizer as seen here, but it does not seem to be taken into account by Retrofit2, although the bean is created:

@Configuration
public class JacksonConfig {

    @Bean
    Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
        return builder -> builder
            .deserializers(new LocalDateTimeDeserializer(MY_DATE_TIME_FORMATTER));
    }
}

Console:

DefaultSingletonBeanRegistry  : Creating shared instance of singleton bean 'jsonCustomizer'
...
com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.time.LocalDateTime` from String "2023-05-26 17:04:52"

Solution

  • If you want to use the customizer, you should inject a Jackson2ObjectMapperBuilder into your bean and use it to build the object mapper.

    e.g.

        @Bean
        SonarqubeClient sonarqubeClient(SonarqubeProperties sonarqubeProperties, Jackson2ObjectMapperBuilder objectMapperBuilder) {
            ObjectMapper objectMapper = objectMapperBuilder.build();