Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Configure a Jackson's DeserializationProblemHandler in Spring environment [duplicate]

As I understood, Spring is already providing a bean for Jackson ObjectMapper. Therefore, instead of creating a new bean, I'm trying to customize this bean.

From this blog post, and then this Github project I used Jackson2ObjectMapperBuilder bean to achieve this customization.

@Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder(ApplicationContext context) {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.findModulesViaServiceLoader(true);
    return builder;
}

Then, I was trying to customize the deserializer in order to make it lenient: if an exception is raised when deserializing a property, I want the result object's property to be null and let the deserialization continue (default is to fail on first property that cannot be deserialized).

I've been able to achieve that with a class NullableFieldsDeserializationProblemHandler that extends DeserializationProblemHandler (I do not think the code is relevant but if needed, I can share it).

The simplest way to register this handler is to use the .addHandler() method of ObjectMapper. But of course, doing like this, I would need to set that every time I inject and use the ObjectMapper. I'd like to be able to configure handler so that every time the ObjectMapper is auto-wired, the handler is already present.

The best solution I came up with so far is to use a @PostConstruct annotation only to register the problem handler.

@Configuration
public class JacksonConfiguration implements InitializingBean {

  @Autowired private ObjectMapper objectMapper;

  @Bean
  public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder(ApplicationContext context) {
    Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    builder.findModulesViaServiceLoader(true);
    return builder;
  }

  @Override
  public void afterPropertiesSet() {
    objectMapper.addHandler(new NullableFieldsDeserializationProblemHandler());
  }
}

But the problem of this solution is that it seems I can still access an autowired ObjectMapper that doesn't have yet registered the problem handler (I can see it happening after when I need it in debug mode).

Any idea how I should register this handler? I've noticed Jackson2ObjectMapperBuilder has a .handlerInstantiator() but I couldn't figure out how to use it.

Note I've also tried with Jackson2ObjectMapperBuilderCustomizer since I'm using Spring Boot but had no better results.

like image 842
woshilapin Avatar asked Sep 13 '25 12:09

woshilapin


1 Answers

It's not possible to directly add a DeserializationProblemHandler to the ObjectMapper via a Jackson2ObjectMapperBuilder or Jackson2ObjectMapperBuilderCustomizer. The handlerInstanciator() method is for something else.

However, it's possible to do so by registering a Jackson module:

  • the builder has a modules() method
  • the module has access via setupModule() to a SetupContext instance, which has a addDeserializationProblemHandler() method

This works:

@Bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
    return new Jackson2ObjectMapperBuilderCustomizer() {
        @Override
        public void customize(Jackson2ObjectMapperBuilder builder) {
            builder.modules(new MyModule());
        }
    };
}

private static class MyModule extends SimpleModule {
    @Override
    public void setupModule(SetupContext context) {
        // Required, as documented in the Javadoc of SimpleModule
        super.setupModule(context);
        context.addDeserializationProblemHandler(new NullableFieldsDeserializationProblemHandler());
    } 
}
like image 93
Frank Pavageau Avatar answered Sep 15 '25 02:09

Frank Pavageau