无法在Spring Boot中将ProblemHandler设置为ObjectMapper

时间:2017-10-09 10:18:20

标签: java spring jackson objectmapper jackson-databind

我尝试使用Jackson2ObjectMapperBuilderCustomizer将自定义问题处理程序添加到对象映射器:

@Bean
public Jackson2ObjectMapperBuilderCustomizer customizer() {
    return new Jackson2ObjectMapperBuilderCustomizer() {
        @Override
        public void customize(Jackson2ObjectMapperBuilder builder) {
            ObjectMapper m = builder.build();
            m.addHandler(
                    new 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);
                        }
                    }
            );
        }
    };
}

但是当我自动装配ObjectMapper bean时,_problemHandlers属性为null。

我也试过用以下方法定制现有的ObjectMapper:

@Autowired
public customize(ObjectMapper mapper) {
...
}

但结果是一样的。我不知道谁可以擦除这个属性。我根本不在另一个地方初始化对象映射器的另一个构建器/工厂/等。我做错了什么?

2 个答案:

答案 0 :(得分:5)

无法通过DeserializationProblemHandlerObjectMapper直接向Jackson2ObjectMapperBuilder添加Jackson2ObjectMapperBuilderCustomizer。在构建器上调用build()是不行的,因为生成的ObjectMapper是方法的本地:Spring本身稍后将调用build(),创建另一个ObjectMapper实例。 / p>

但是,可以通过注册Jackson模块来实现:

  • 构建器具有modules()方法
  • 该模块可通过setupModule()访问SetupContext实例,该实例具有addDeserializationProblemHandler()方法

这应该有效

@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);
    }
}

答案 1 :(得分:0)

我是 Spring Boot 的新手,所以很难理解如何使用它。但是经过一番研究,我设法弄清楚了。

我必须创建一个名为 src.main.java.com.applicationname.config.JacksonUnknownPropertyConfig.java 的类,其内容为:

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);
    }
  }
}

我还必须将 FAIL_ON_UNKNOWN_PROPERTIES 添加到文件 src.main.resources.application.properties

spring.jackson.deserialization.FAIL_ON_UNKNOWN_PROPERTIES=true

此后,看起来 Sprint Boot 会自动识别我创建的新类并正确加载它。

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

相关线程:

  1. Spring Boot, Spring MVC JSON RequestBody: Unknown property ignored
  2. How to customise Jackson in Spring Boot 1.4
  3. jackson Unrecognized field
  4. Ignoring new fields on JSON objects using Jackson
  5. Configure FAIL_ON_UNKNOWN_PROPERTIES for each RequestMapping differently in the Controller
  6. Jackson deserializer priority?
  7. Spring Data Elastic - Java.Time.Instant class Jackson deserliization not working
  8. Enable Jackson Deserialization of Empty Objects to Null
  9. Spring RestController : reject request with unknown fields
  10. How do you globally set Jackson to ignore unknown properties within Spring?
  11. https://www.baeldung.com/spring-bean
  12. https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto-spring-mvc