From d900e1ca2118b82e44e673cf4b070b73e4046eee Mon Sep 17 00:00:00 2001 From: Anupam Chaubey Date: Sat, 19 Sep 2026 03:33:29 +0530 Subject: [PATCH 1/2] fix: make CollectionModelContentConverter conditional on LinkRelationProvider bean Add @ConditionalOnBean(LinkRelationProvider.class) so the configuration does not fail when the class is present but no bean exists. Fixes #3364 --- .../core/configuration/SpringDocHateoasConfiguration.java | 1 + 1 file changed, 1 insertion(+) 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..c2b20b10a 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 @@ -126,6 +126,7 @@ HateoasHalProvider hateoasHalProvider(ObjectMapperProvider objectMapperProvider) */ @Bean @ConditionalOnMissingBean + @ConditionalOnBean(LinkRelationProvider.class) @Lazy(false) CollectionModelContentConverter collectionModelContentConverter(HateoasHalProvider halProvider, LinkRelationProvider linkRelationProvider) { return halProvider.isHalEnabled() ? new CollectionModelContentConverter(linkRelationProvider) : null; From 54695f1c7b2abdbe0266798b900b56b541bc7485 Mon Sep 17 00:00:00 2001 From: Anupam Chaubey Date: Sat, 19 Sep 2026 15:11:33 +0530 Subject: [PATCH 2/2] fix: make CollectionModelContentConverter conditional on LinkRelationProvider bean Add @ConditionalOnBean(LinkRelationProvider.class) via a nested configuration so the converter is only created when the bean exists. Application context no longer fails when the class is present but no bean is available. Also extend the unit tests to cover both presence and absence of the bean. Fixes #3364 --- .../SpringDocHateoasConfiguration.java | 29 ++++++++++++------- .../SpringDocHateoasConfigurationTest.java | 28 ++++++++++++++++++ 2 files changed, 47 insertions(+), 10 deletions(-) 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 c2b20b10a..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,18 +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 + @Configuration(proxyBeanMethods = false) @ConditionalOnBean(LinkRelationProvider.class) - @Lazy(false) - CollectionModelContentConverter collectionModelContentConverter(HateoasHalProvider halProvider, LinkRelationProvider linkRelationProvider) { - return halProvider.isHalEnabled() ? new CollectionModelContentConverter(linkRelationProvider) : null; + 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