Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson module not registered after update to Spring Boot 2

I'm as upgrading from Spring Boot 1.5.21 to 2.2.5.

I need to use MonetaryModule to deserialize rest calls, and depending on Spring's ObjectMapper.

I have defined such a bean for this module in a some @Configuration class (MonetaryModule is extending Module):

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

I can see in /beans endpoint it was created. However, it is not actually loaded to ObjectMapper. After a lot of debugging and digging around Spring's code, I came to the conclusion that there is something wrong in JacksonAutoConfiguration. it has an inner static class called JacksonObjectMapperBuilderConfiguration and in it there's a bean that creates the Jackson2ObjectMapperBuilder. in the creation process, there's a call to customize() that eventually gets to this code:

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

This code seems responsible for loading the modules into ObjectMapper, Problem is that this Jackson2ObjectMapperBuilder is not actually created. It appears in /beans endpoint but de facto when I breakpoint there I'm not hitting the breakpoint. This explains why the module is not loaded into ObjectMapper.

Question is, why is this code not being called? and why /bean indicates the bean does exist?

Edit - Adding conditions evaluation report:

============================
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

Also, attached is the output of /conditions & /beans endpoints output (Too large to paste into the post itself)

endpoints output

like image 497
Eyal Ringort Avatar asked May 07 '20 11:05

Eyal Ringort


People also ask

Is Jackson Databind included in spring boot?

If you use Spring Boot, the jackson-databind dependency comes in the spring-boot-starter-json module (which also is included in other spring boot started moduled, like spring-boot-starter-web ).

What is Jackson afterburner?

Jackson (https://github.com/FasterXML/jackson) extension module used to enhance performance using bytecode generation to replace use of Reflection for field access and method calls.

Does spring boot have Jackson ObjectMapper?

Overview. When using JSON format, Spring Boot will use an ObjectMapper instance to serialize responses and deserialize requests. In this tutorial, we'll take a look at the most common ways to configure the serialization and deserialization options. To learn more about Jackson, be sure to check out our Jackson tutorial.

Does spring use Jackson by default?

Spring Framework and Spring Boot provide builtin support for Jackson based XML serialization/deserialization. As soon as you include the jackson-dataformat-xml dependency to your project, it is automatically used instead of JAXB2.


1 Answers

Your condition evaluation report shows the following:

        "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": []
        },

This means that the Spring Boot auto-configuration condition is backing off since your application already provides an opinion on the matter: there is already an ObjectMapper bean named jacksonBuilder; it is provided by the application or some configuration class in a library you're using.

In this case, this comes from a configuration class, as pointed out by the beans endpoint:

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

You should here get in touch with the maintainers of this AuthorizationDomainConfiguration and let them know that they should avoid overriding the opinion of the application on JSON (de)serialization.

like image 135
Brian Clozel Avatar answered Nov 11 '22 18:11

Brian Clozel