Reputation: 41
We have an existing Spring application which is packaged as a war file.
We recently migrated from Swagger 2 to Springdoc-openapi, but we are having trouble getting our application to start with a working Springdoc configuration.
Our configuration looks as follows:
@Configuration
@ComponentScan(basePackages = {"org.springdoc"})
@EnableWebMvc
@Import({SpringDocConfiguration.class,
SpringDocWebMvcConfiguration.class,
org.springdoc.webmvc.ui.SwaggerConfig.class,
SwaggerUiConfigProperties.class,
SwaggerUiOAuthProperties.class,
JacksonAutoConfiguration.class})
public class OpenApiConfiguration implements WebMvcConfigurer {
@Bean
public OpenAPI openAPI() {
return new OpenAPI();
}
}
We have the following dependencies, with spring.version=6.0.11
:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
When we start the application, we receive the following error:
2023-08-08 17:01:40,702 \[RMI TCP Connection(2)-127.0.0.1\] ERROR org.springframework.web.context.ContextLoader - \[\] Context initialization failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'openApiWebMvcResource' defined in URL \[jar:file:/Users/.../WEB-INF/lib/springdoc-openapi-starter-webmvc-api-2.1.0.jar!/org/springdoc/webmvc/api/OpenApiWebMvcResource.class\]: Unsatisfied dependency expressed through constructor parameter 5: Error creating bean with name 'springDocProviders' defined in org.springdoc.core.configuration.SpringDocConfiguration: Unsatisfied dependency expressed through method 'springDocProviders' parameter 3: Error creating bean with name 'springRepositoryRestResourceProvider' defined in org.springdoc.core.configuration.SpringDocDataRestConfiguration$SpringRepositoryRestResourceProviderConfiguration: Unsatisfied dependency expressed through method 'springRepositoryRestResourceProvider' parameter 0: No qualifying bean of type 'org.springframework.data.rest.core.mapping.ResourceMappings' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800) \~\[spring-beans-6.0.11.jar:6.0.11\]
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:245) \~\[spring-beans-6.0.11.jar:6.0.11\]
...
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'springDocProviders' defined in org.springdoc.core.configuration.SpringDocConfiguration: Unsatisfied dependency expressed through method 'springDocProviders' parameter 3: Error creating bean with name 'springRepositoryRestResourceProvider' defined in org.springdoc.core.configuration.SpringDocDataRestConfiguration$SpringRepositoryRestResourceProviderConfiguration: Unsatisfied dependency expressed through method 'springRepositoryRestResourceProvider' parameter 0: No qualifying bean of type 'org.springframework.data.rest.core.mapping.ResourceMappings' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800) \~\[spring-beans-6.0.11.jar:6.0.11\]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:550) \~\[spring-beans-6.0.11.jar:6.0.11\]
at
...
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'springRepositoryRestResourceProvider' defined in org.springdoc.core.configuration.SpringDocDataRestConfiguration$SpringRepositoryRestResourceProviderConfiguration: Unsatisfied dependency expressed through method 'springRepositoryRestResourceProvider' parameter 0: No qualifying bean of type 'org.springframework.data.rest.core.mapping.ResourceMappings' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800) \~\[spring-beans-6.0.11.jar:6.0.11\]
We note that others on Stack Overflow have had a problem starting a non-boot application with Springdoc but they received a different error.
On Springdoc's GitHub there is another mention of how to configure a non-boot application but the solution recommended there, to add @ComponentScan(basePackages = {"org.springdoc"})
doesn't fix the issue.
Any help is appreciated!
Upvotes: 1
Views: 2379
Reputation: 41
We have now resolved this issue, with thanks to the folks over on Springdoc's GitHub project.
We created a test project to demo the issue here.
As per this answer to our GitHub ticket, The fix was as follows:
In the case of our demo application, the exclusion of the relevant configuration class can be done as per the answer on GitHub, using @EnableAutoConfiguration(exclude=SpringDocDataRestConfiguration.class)
In the case of our actual application, we ended up using custom filters to exclude both SpringDocDataRestConfiguration
and SpringDocHateoasConfiguration
, as per this comment, i.e.
@Configuration
@ComponentScan(
basePackages = {"org.springdoc"},
excludeFilters = {@ComponentScan.Filter(
type = FilterType.CUSTOM,
classes = {
OpenApiConfiguration.SpringDocDataRestFilter.class,
OpenApiConfiguration.SpringDocHateoasFilter.class
}
)}
)
public class OpenApiConfiguration {
@Bean
public OpenAPI openAPI() {
return new OpenAPI();
}
public static class SpringDocDataRestFilter extends ClassFilter {
@Override
protected Class<?> getFilteredClass() {
return SpringDocDataRestConfiguration.class;
}
}
public static class SpringDocHateoasFilter extends ClassFilter {
@Override
protected Class<?> getFilteredClass() {
return SpringDocHateoasConfiguration.class;
}
}
private static abstract class ClassFilter implements TypeFilter {
protected abstract Class<?> getFilteredClass();
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
String className = metadataReader.getClassMetadata().getClassName();
String enclosingClassName = metadataReader.getClassMetadata().getEnclosingClassName();
return
className.equals(getFilteredClass().getCanonicalName())
|| (enclosingClassName!=null && enclosingClassName.equals(getFilteredClass().getCanonicalName()));
}
}
}
Upvotes: 2