diff --git a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocHateoasConfiguration.java b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocHateoasConfiguration.java index a79ac4da7..908bd67e0 100644 --- a/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocHateoasConfiguration.java +++ b/springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocHateoasConfiguration.java @@ -118,17 +118,27 @@ HateoasHalProvider hateoasHalProvider(ObjectMapperProvider objectMapperProvider) } /** - * Collection model content converter collection model content converter. - * - * @param halProvider the hal provider - * @param linkRelationProvider the link relation provider - * @return the collection model content converter + * Creates CollectionModelContentConverter only when a LinkRelationProvider bean exists. */ - @Bean - @ConditionalOnMissingBean - @Lazy(false) - CollectionModelContentConverter collectionModelContentConverter(HateoasHalProvider halProvider, LinkRelationProvider linkRelationProvider) { - return halProvider.isHalEnabled() ? new CollectionModelContentConverter(linkRelationProvider) : null; + @Configuration(proxyBeanMethods = false) + @ConditionalOnBean(LinkRelationProvider.class) + static class CollectionModelContentConverterConfiguration { + + /** + * Collection model content converter collection model content converter. + * + * @param halProvider the hal provider + * @param linkRelationProvider the link relation provider + * @return the collection model content converter + */ + @Bean + @ConditionalOnMissingBean + @Lazy(false) + CollectionModelContentConverter collectionModelContentConverter( + HateoasHalProvider halProvider, + LinkRelationProvider linkRelationProvider) { + return halProvider.isHalEnabled() ? new CollectionModelContentConverter(linkRelationProvider) : null; + } } /** diff --git a/springdoc-openapi-starter-common/src/test/java/org/springdoc/core/configuration/SpringDocHateoasConfigurationTest.java b/springdoc-openapi-starter-common/src/test/java/org/springdoc/core/configuration/SpringDocHateoasConfigurationTest.java index 7db8bb8e7..182d8c83f 100644 --- a/springdoc-openapi-starter-common/src/test/java/org/springdoc/core/configuration/SpringDocHateoasConfigurationTest.java +++ b/springdoc-openapi-starter-common/src/test/java/org/springdoc/core/configuration/SpringDocHateoasConfigurationTest.java @@ -15,6 +15,7 @@ import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration; import org.springframework.hateoas.config.HateoasConfiguration; +import org.springframework.hateoas.server.LinkRelationProvider; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -92,6 +93,7 @@ void linksSchemaCustomizerShouldNotBeRegisteredIfBeanWithSameNameAlreadyExists() @Test void halBeansShouldBeRegisteredWhenHateoasPropertiesIsPresent() { hateoasContextRunner() + .withBean(LinkRelationProvider.class, () -> mock(LinkRelationProvider.class)) // ← add this .run(context -> { assertThat(context).hasNotFailed(); assertThat(context).hasSingleBean(HateoasHalProvider.class); @@ -111,6 +113,7 @@ void halBeansShouldBeRegisteredWhenHateoasPropertiesIsPresent() { void halBeansShouldBeRegisteredWhenHateoasPropertiesIsAbsent() { hateoasContextRunner() .withClassLoader(new FilteredClassLoader(HateoasProperties.class)) + .withBean(LinkRelationProvider.class, () -> mock(LinkRelationProvider.class)) // ← add this .run(context -> { assertThat(context).hasNotFailed(); assertThat(context).hasSingleBean(HateoasHalProvider.class); @@ -134,4 +137,29 @@ private WebApplicationContextRunner hateoasContextRunner() { SpringDocHateoasConfiguration.class )); } + + /** + * LinkRelationProvider class may be on the classpath while no bean of that type + * is present. The application context must still start and + * CollectionModelContentConverter must not be created. + */ + @Test + void collectionModelContentConverterShouldNotBeCreatedWhenLinkRelationProviderBeanIsAbsent() { + new WebApplicationContextRunner() + .withPropertyValues( + "springdoc.api-docs.enabled=true", + "springdoc.enable-hateoas=true" + ) + .withConfiguration(AutoConfigurations.of( + WebMvcAutoConfiguration.class, + // deliberately omit HateoasConfiguration → no LinkRelationProvider bean + SpringDocConfiguration.class, + SpringDocConfigProperties.class, + SpringDocHateoasConfiguration.class + )) + .run(context -> { + assertThat(context).hasNotFailed(); + assertThat(context).doesNotHaveBean(CollectionModelContentConverter.class); + }); + } } \ No newline at end of file