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)
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.