简体   繁体   English

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

[英]Can't set ProblemHandler to ObjectMapper in Spring Boot

I tried to add custom problem handler to object mapper with Jackson2ObjectMapperBuilderCustomizer:我尝试使用 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);
                        }
                    }
            );
        }
    };
}

But when i autowired ObjectMapper bean _problemHandlers property is null.但是当我自动装配 ObjectMapper bean _problemHandlers 属性为空时。

I also tried just customize existed ObjectMapper with:我还尝试使用以下方法自定义现有的 ObjectMapper:

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

But result is the same.但结果是一样的。 I don't know who can erasure this property.我不知道谁能删除这个属性。 I don't initialize another builders/factories/etc of object mapper in another place at all.我根本不会在另一个地方初始化对象映射器的另一个构建器/工厂/等。 What i'm doing wrong?我做错了什么?

It's not possible to directly add a DeserializationProblemHandler to the ObjectMapper via a Jackson2ObjectMapperBuilder or Jackson2ObjectMapperBuilderCustomizer .无法通过Jackson2ObjectMapperBuilderJackson2ObjectMapperBuilderCustomizer直接将DeserializationProblemHandler添加到ObjectMapper 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.在构建器上调用build()是不行的,因为生成的ObjectMapper是该方法的本地:Spring 本身稍后会调用build() ,创建另一个ObjectMapper实例。

However, it's possible to do so by registering a Jackson module :但是,可以通过注册 Jackson 模块来做到这一点:

  • the builder has a modules() method构建器有一个modules()方法
  • the module has access via setupModule() to a SetupContext instance, which has a addDeserializationProblemHandler() method模块可以通过setupModule()访问SetupContext实例,该实例具有addDeserializationProblemHandler()方法

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

EDIT (2022-06-27)编辑 (2022-06-27)

As mentioned by E-Riz in the comments, with newer Spring Boot versions you can just register the module as a Spring Bean and it will be configured on the ObjectMapper with all the other modules .正如 E-Riz 在评论中提到的,对于较新的 Spring Boot 版本,您只需将模块注册为 Spring Bean,它将在ObjectMapper上与所有其他模块一起配置。

// Or declare it as a @Bean in a @Configuration
@Component
public 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);
        }
    }
}

I am new to Spring Boot , then, it was difficult to understand how I could use this.我是Spring Boot的新手,因此很难理解如何使用它。 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:我必须创建一个名为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);
    }
  }
}

And I also had to add FAIL_ON_UNKNOWN_PROPERTIES to the file src.main.resources.application.properties而且我还必须将FAIL_ON_UNKNOWN_PROPERTIES添加到文件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.在此之后,看起来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

Related threads:相关话题:

  1. Spring Boot, Spring MVC JSON RequestBody: Unknown property ignored Spring Boot,Spring MVC JSON RequestBody:未知属性被忽略
  2. How to customise Jackson in Spring Boot 1.4 如何在 Spring Boot 1.4 中自定义 Jackson
  3. jackson Unrecognized field 杰克逊无法识别的字段
  4. Ignoring new fields on JSON objects using Jackson 使用 Jackson 忽略 JSON 对象上的新字段
  5. Configure FAIL_ON_UNKNOWN_PROPERTIES for each RequestMapping differently in the Controller 在 Controller 中为每个 RequestMapping 配置不同的 FAIL_ON_UNKNOWN_PROPERTIES
  6. Jackson deserializer priority? 杰克逊解串器优先级?
  7. Spring Data Elastic - Java.Time.Instant class Jackson deserliization not working Spring Data Elastic - Java.Time.Instant 类杰克逊反序列化不起作用
  8. Enable Jackson Deserialization of Empty Objects to Null 启用 Jackson 将空对象反序列化为 Null
  9. Spring RestController : reject request with unknown fields Spring RestController:拒绝带有未知字段的请求
  10. How do you globally set Jackson to ignore unknown properties within Spring? 您如何全局设置 Jackson 以忽略 Spring 中的未知属性?
  11. https://www.baeldung.com/spring-bean https://www.baeldung.com/spring-bean
  12. https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto-spring-mvc https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto-spring-mvc

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Spring Boot 和 ObjectMapper 配置 - Spring Boot and ObjectMapper configuration 升级到 Spring Boot 2 后,ObjectMapper 无法在没有默认构造函数的情况下反序列化 - ObjectMapper can't deserialize without default constructor after upgrade to Spring Boot 2 spring 引导中的 ObjectMapper 可以读取字符串,但在解析标头时不起作用 - ObjectMapper in spring boot can read string, but doesn't work when parsing headers RepositoryRestMvcConfiguration的ObjectMapper与Spring Boot默认的ObjectMapper? - RepositoryRestMvcConfiguration's ObjectMapper vs. Spring Boot default ObjectMapper? 使用 Jackson Objectmapper 配置的 Spring boot in Hibernate - Use Jackson Objectmapper configured by Spring boot in Hibernate 为什么 Spring 引导不使用自定义 ObjectMapper bean? - Why Spring Boot not using custom ObjectMapper bean? 无法从 Spring 引导应用程序中设置的 DBRef 中删除 - Can't remove from DBRef set in Spring Boot application 什么是 Spring 启动 ObjectMapper Bean 范围? - What is the Spring boot ObjectMapper Bean scope? 如何在 Spring 引导中为 Camel 配置 Jackson ObjectMapper - How to configure Jackson ObjectMapper for Camel in Spring Boot 无法在 Spring Boot 中设置 Strict-Transport-Security 标头 - Can't set the Strict-Transport-Security header in Spring Boot
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM