I tried to add custom problem handler to object mapper with Jackson2ObjectMapperBuilderCustomizer:
@Bean
public Jackson2ObjectMapperBuilderCustomizer customi
I am new to Spring Boot
, then, it was difficult to understand how I could use this. But after some research I managed to figure out.
I had to create a class named src.main.java.com.applicationname.config.JacksonUnknownPropertyConfig.java
with the contents:
package com.applicationname.config;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.web.server.ResponseStatusException;
import java.io.IOException;
@SpringBootConfiguration
public class JacksonUnknownPropertyConfig {
private static final Logger logger = LoggerFactory.getLogger(JacksonUnknownPropertyConfig.class);
@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 MyDeserializationProblemHandler());
}
}
private static class MyDeserializationProblemHandler extends DeserializationProblemHandler {
@Override
public boolean handleUnknownProperty(
DeserializationContext ctxt,
JsonParser p,
JsonDeserializer<?> deserializer,
Object beanOrClass,
String propertyName)
throws IOException {
System.out.println("ahahahaa");
final String missing = String.format("Unknown request property '%s'", propertyName);
logger.warn(missing);
if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, missing);
}
return super.handleUnknownProperty(ctxt, p, deserializer, beanOrClass, propertyName);
}
}
}
And I also had to add FAIL_ON_UNKNOWN_PROPERTIES
to the file src.main.resources.application.properties
spring.jackson.deserialization.FAIL_ON_UNKNOWN_PROPERTIES=true
After this, looks like Sprint Boot
automatically recognizes the new class I created and correctly loads it.
2020-07-20 23:41:22.934 INFO 16684 --- [ task-1] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2020-07-20 23:41:22.944 TRACE 16684 --- [ task-1] o.h.type.spi.TypeConfiguration$Scope : Handling #sessionFactoryCreated from [org.hibernate.internal.SessionFactoryImpl@3edd0926] for TypeConfiguration
2020-07-20 23:41:22.946 INFO 16684 --- [ task-1] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2020-07-20 23:41:23.209 INFO 16684 --- [ main] DeferredRepositoryInitializationListener : Spring Data repositories initialized!
2020-07-20 23:41:23.222 INFO 16684 --- [ main] c.a.p.AppointmentPublishingApplication : Started AppointmentPublishingApplication in 6.445 seconds (JVM running for 7.615)
2020-07-20 23:41:26.229 INFO 16684 --- [nio-8081-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-07-20 23:41:26.229 INFO 16684 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-07-20 23:41:26.236 INFO 16684 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 7 ms
ahahahaa
Related threads:
It's not possible to directly add a DeserializationProblemHandler
to the ObjectMapper
via a Jackson2ObjectMapperBuilder
or Jackson2ObjectMapperBuilderCustomizer
. Calling build()
on the builder is a no-go, since the resulting ObjectMapper
is local to the method: Spring itself will call build()
later, creating another ObjectMapper
instance.
However, it's possible to do so by registering a Jackson module :
modules()
methodsetupModule()
to a SetupContext
instance, which has a addDeserializationProblemHandler()
methodThis should then work
@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 MyDeserializationProblemHandler());
}
}
private static class MyDeserializationProblemHandler extends DeserializationProblemHandler {
@Override
public boolean handleUnknownProperty(DeserializationContext ctxt,
JsonParser p,
JsonDeserializer<?> deserializer,
Object beanOrClass,
String propertyName)
throws IOException {
System.out.println("ahahahaa");
return super.handleUnknownProperty(ctxt, p, deserializer, beanOrClass, propertyName);
}
}