Description
We have a big multi-module repository of several Spring Boot applications.
Some of these applications run as web apps, some are mere background services using org.springframework.boot.WebApplicationType.NONE
.
Even for these background services we might (transitively) depend on springdoc-openapi.
With springdoc-openapi 1.6.9 we observe application start-up failures for our non-web apps:
Jul 07 09:23:16 our-app: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springdoc.kotlin.SpringDocKotlinConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springdoc.core.providers.ObjectMapperProvider' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229)
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1372)
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1222)
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955)
Jul 07 09:23:16 our-app: at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
Jul 07 09:23:16 our-app: at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
Jul 07 09:23:16 our-app: at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734)
Jul 07 09:23:16 our-app: at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408)
Jul 07 09:23:16 our-app: at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
Jul 07 09:23:16 our-app: at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:164)
...
Jul 07 09:23:16 our-app: Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springdoc.core.providers.ObjectMapperProvider' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1801)
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1357)
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1311)
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
Jul 07 09:23:16 our-app: at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
Jul 07 09:23:16 our-app: ... 39 more
We traced the issue to a mismatching auto configuration @Condition
, where org.springdoc.kotlin.SpringDocKotlinConfiguration
(in springdoc-openapi-kotlin) is instantiated whenever springdoc-openapi is enabled, however it's constructor parameter depdendency org.springdoc.core.providers.ObjectMapperProvider
is instantiated by org.springdoc.core.SpringDocConfiguration
(in springdoc-openapi-common) which itself gets only instantiated in a web application context (@ConditionalOnWebApplication
).
To Reproduce
Using Kotlin 1.6.20, Spring Boot 2.6.9 and springdoc-openapi 1.6.9, build a minimal Spring Boot application that explicitly sets WebApplicationType.NONE
. Put springdoc-openapi-kotlin on the class path and attempt to start the application.
Expected behavior
Application start-up should not be hindered by having springdoc-openapi modules on the class path, even if the application is not a web app. We would either expect org.springdoc.kotlin.SpringDocKotlinConfiguration
being only applied in web applications, or alternatively have the org.springdoc.core.providers.ObjectMapperProvider
available regardless of web application type.