更新到 Spring Boot 2 后 Jackson 模块未注册

Posted

技术标签:

【中文标题】更新到 Spring Boot 2 后 Jackson 模块未注册【英文标题】:Jackson module not registered after update to Spring Boot 2 【发布时间】:2020-08-22 16:50:31 【问题描述】:

我正在从 Spring Boot 1.5.21 升级到 2.2.5。

我需要使用MonetaryModule 来反序列化rest 调用,这取决于Spring 的ObjectMapper

我在某个@Configuration 类中为这个模块定义了这样一个bean(MonetaryModule 正在扩展Module):

@Bean
public MonetaryModule monetaryModule() 
    return new MonetaryModule();

我可以在/beans 端点中看到它已创建。但是,它实际上并未加载到ObjectMapper。在对 Spring 的代码进行了大量的调试和挖掘之后,我得出的结论是 JacksonAutoConfiguration 有问题。它有一个名为JacksonObjectMapperBuilderConfiguration 的内部静态类,其中有一个bean 创建Jackson2ObjectMapperBuilder。在创建过程中,调用customize() 最终会得到以下代码:

private void configureModules(Jackson2ObjectMapperBuilder builder) 
    Collection<Module> moduleBeans = getBeans(this.applicationContext, Module.class);
    builder.modulesToInstall(moduleBeans.toArray(new Module[0]));

这段代码似乎负责将模块加载到ObjectMapper,问题是这个Jackson2ObjectMapperBuilder实际上并没有创建。它出现在/beans 端点中,但事实上,当我在那里断点时,我没有到达断点。这就解释了为什么模块没有加载到ObjectMapper

问题是,为什么这段代码没有被调用?为什么/bean 表明该bean 确实存在?

编辑-添加条件评估报告:

============================
CONDITIONS EVALUATION REPORT
============================


Positive matches:
-----------------

   AopAutoConfiguration matched:
      - @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)

   AopAutoConfiguration.AspectJAutoProxyingConfiguration matched:
      - @ConditionalOnClass found required class 'org.aspectj.weaver.Advice' (OnClassCondition)

   AopAutoConfiguration.AspectJAutoProxyingConfiguration.CglibAutoProxyConfiguration matched:
      - @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition)

   ConfigServiceBootstrapConfiguration#configServicePropertySource matched:
      - @ConditionalOnProperty (spring.cloud.config.enabled) matched (OnPropertyCondition)
      - @ConditionalOnMissingBean (types: org.springframework.cloud.config.client.ConfigServicePropertySourceLocator; SearchStrategy: all) did not find any beans (OnBeanCondition)

   ConfigServiceBootstrapConfiguration.RetryConfiguration matched:
      - @ConditionalOnClass found required classes 'org.springframework.retry.annotation.Retryable', 'org.aspectj.lang.annotation.Aspect', 'org.springframework.boot.autoconfigure.aop.AopAutoConfiguration' (OnClassCondition)
      - @ConditionalOnProperty (spring.cloud.config.fail-fast) matched (OnPropertyCondition)

   ConfigServiceBootstrapConfiguration.RetryConfiguration#configServerRetryInterceptor matched:
      - @ConditionalOnMissingBean (names: configServerRetryInterceptor; SearchStrategy: all) did not find any beans (OnBeanCondition)

   ConfigurationPropertiesRebinderAutoConfiguration matched:
      - @ConditionalOnBean (types: org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor; SearchStrategy: all) found bean 'org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor' (OnBeanCondition)

   ConfigurationPropertiesRebinderAutoConfiguration#configurationPropertiesBeans matched:
      - @ConditionalOnMissingBean (types: org.springframework.cloud.context.properties.ConfigurationPropertiesBeans; SearchStrategy: current) did not find any beans (OnBeanCondition)

   ConfigurationPropertiesRebinderAutoConfiguration#configurationPropertiesRebinder matched:
      - @ConditionalOnMissingBean (types: org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder; SearchStrategy: current) did not find any beans (OnBeanCondition)

   EncryptionBootstrapConfiguration matched:
      - @ConditionalOnClass found required class 'org.springframework.security.crypto.encrypt.TextEncryptor' (OnClassCondition)

   PropertyPlaceholderAutoConfiguration#propertySourcesPlaceholderConfigurer matched:
      - @ConditionalOnMissingBean (types: org.springframework.context.support.PropertySourcesPlaceholderConfigurer; SearchStrategy: current) did not find any beans (OnBeanCondition)


Negative matches:
-----------------

   AopAutoConfiguration.AspectJAutoProxyingConfiguration.JdkDynamicAutoProxyConfiguration:
      Did not match:
         - @ConditionalOnProperty (spring.aop.proxy-target-class=false) did not find property 'proxy-target-class' (OnPropertyCondition)

   AopAutoConfiguration.ClassProxyingConfiguration:
      Did not match:
         - @ConditionalOnMissingClass found unwanted class 'org.aspectj.weaver.Advice' (OnClassCondition)

   DiscoveryClientConfigServiceBootstrapConfiguration:
      Did not match:
         - @ConditionalOnProperty (spring.cloud.config.discovery.enabled) did not find property 'spring.cloud.config.discovery.enabled' (OnPropertyCondition)

   EncryptionBootstrapConfiguration.RsaEncryptionConfiguration:
      Did not match:
         - Keystore nor key found in Environment (EncryptionBootstrapConfiguration.KeyCondition)
      Matched:
         - @ConditionalOnClass found required class 'org.springframework.security.rsa.crypto.RsaSecretEncryptor' (OnClassCondition)

   EncryptionBootstrapConfiguration.VanillaEncryptionConfiguration:
      Did not match:
         - @ConditionalOnMissingClass found unwanted class 'org.springframework.security.rsa.crypto.RsaSecretEncryptor' (OnClassCondition)


Exclusions:
-----------

    None


Unconditional classes:
----------------------

    None

另外,附上/conditions/beans 端点输出的输出(太大,无法粘贴到帖子本身)

endpoints output

【问题讨论】:

任何具有自己的自动配置(...并创建 Jackson2ObjectMapperBuilder)的库? 我不知道... 你试过调试Jackson2ObjectMapperBuilder的默认构造函数吗? (至少在 Intellij Idea 中应该是可能的,根据一些快速的谷歌搜索,Eclipse 似乎也知道这一点。) Jackson2ObjectMapperBuilder 的 CTOR 在我调试的 MappingJackson2CborHttpMessageConverter 中使用(在我的场景中)。它不包含所需的模块。 您可以尝试在此处提供更多信息(您的主应用程序类、应用程序属性、WebMvcConfigurer 自定义类、自动配置报告)或尝试在您可以共享的小项目中重现问题。如果没有这些,恐怕我们无法帮助您。 【参考方案1】:

您的病情评估报告显示如下:

        "JacksonAutoConfiguration.JacksonObjectMapperConfiguration#jacksonObjectMapper": 
          "notMatched": [
            
              "condition": "OnBeanCondition",
              "message": "@ConditionalOnMissingBean (types: com.fasterxml.jackson.databind.ObjectMapper; SearchStrategy: all) found beans of type 'com.fasterxml.jackson.databind.ObjectMapper' jacksonBuilder"
            
          ],
          "matched": []
        ,

这意味着 Spring Boot 自动配置条件正在退出,因为您的应用程序已经就此事提供了意见:已经有一个名为 jacksonBuilderObjectMapper bean;它由应用程序或您正在使用的库中的某个配置类提供。

在这种情况下,这来自一个配置类,正如 bean 端点所指出的那样:

        "jacksonBuilder": 
          "aliases": [],
          "scope": "singleton",
          "type": "com.fasterxml.jackson.databind.ObjectMapper",
          "resource": "class path resource [com/behalf/core/authorization_domain/config/AuthorizationDomainConfiguration.class]",
          "dependencies": []
        ,

您应该在这里与AuthorizationDomainConfiguration 的维护者取得联系,并让他们知道他们应该避免覆盖应用程序对 JSON(反)序列化的意见。

【讨论】:

就是这样!非常感谢!

以上是关于更新到 Spring Boot 2 后 Jackson 模块未注册的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot cloud vault 更新到 3.0.3 版本后不再加载属性

更新到 Spring Boot 1.5.8 和 Finchley/Edgware Spring Cloud 后 Feign Exception 403

未使用 Spring Boot 2.3 调用 RestControllerAdvice

Spring Boot - 从 2.2.5 升级到 2.3.0 后验证停止工作

独立资源服务器(Spring Boot 2 + OAuth + JWT)在 Spring-boot 从 1.2.x 升级到 2.x 后给出 UsernameNotFoundException

升级到 Spring Boot 2.0.2 后 Spring Security .permitAll() 不再有效