spring-data-commons icon indicating copy to clipboard operation
spring-data-commons copied to clipboard

using @EnableSpringDataWebSupport with spring-data-rest results in BeanDefinitionOverrideException

Open zyro23 opened this issue 1 year ago • 5 comments

adding @EnableSpringDataWebSupport in a project that uses spring-boot-starter-data-rest results in a BeanDefinitionOverrideException preventing application startup.

context: i want to use PageSerializationMode.VIA_DTO. while that "just worked" by default with spring-data-commons 3.3.0, from 3.3.1 on we have to add @EnableSpringDataWebSupport(pageSerializationMode = EnableSpringDataWebSupport.PageSerializationMode.VIA_DTO) explicitly (due to #3101).

sample app (boot-3.3.1-SNAPSHOT, spring-data-bom-2024.0.1-SNAPSHOT, spring-data-commons-3.3.1-SNAPSHOT at the time of writing) will be referenced asap.

2024-06-15T10:28:59.121+02:00  INFO 26728 --- [demo] [           main] com.example.demo.DemoApplication         : Starting DemoApplication using Java 21.0.1 with PID 26728 [...]
2024-06-15T10:28:59.123+02:00  INFO 26728 --- [demo] [           main] com.example.demo.DemoApplication         : No active profile set, falling back to 1 default profile: "default"
2024-06-15T10:28:59.450+02:00  WARN 26728 --- [demo] [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'pageableResolver' defined in class path resource [org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.class]: Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration; factoryMethodName=pageableResolver; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in class path resource [org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.class]] for bean 'pageableResolver' since there is already [Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.data.web.config.HateoasAwareSpringDataWebConfiguration; factoryMethodName=pageableResolver; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in class path resource [org/springframework/data/web/config/HateoasAwareSpringDataWebConfiguration.class]] bound.
2024-06-15T10:28:59.455+02:00  INFO 26728 --- [demo] [           main] .s.b.a.l.ConditionEvaluationReportLogger : 

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2024-06-15T10:28:59.468+02:00 ERROR 26728 --- [demo] [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

The bean 'pageableResolver', defined in class path resource [org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/data/web/config/HateoasAwareSpringDataWebConfiguration.class] and overriding is disabled.

Action:

Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

zyro23 avatar Jun 15 '24 08:06 zyro23

https://github.com/spring-projects/spring-boot/pull/39797 is trying to fix this.

quaff avatar Jun 20 '24 02:06 quaff

For me the problem was that I also had spring-boot-starter-data-rest in my dependencies. This caused the clashing of the beans when the application booted. @zyro23 Maybe that fixes the issue on your side as well?

devtobi avatar Mar 07 '25 08:03 devtobi

but i think thats exactly the point - we want to have spring-boot-starter-data-rest for rest repositories alongside spring-data's web support (i.e. @EnableSpringDataWebSupport/PageSerializationMode.VIA_DTO, preferably auto-configured) for custom (non-rest) repositories.

our current workaround looks like this:

spring:
  data:
    web:
      pageable:
        serialization-mode: via-dto
/**
 * in order to use spring-data-rest with hateos for repository rest resources alongside spring-data-web with {@link PageSerializationMode#VIA_DTO},
 * we enable {@link SpringDataWebProperties} and register {@link SpringDataWebSettings} manually
 * because {@link SpringDataWebAutoConfiguration} is not applied due to {@link RepositoryRestMvcAutoConfiguration} taking precedence
 * (@{@link AutoConfiguration}(after = {@link RepositoryRestMvcAutoConfiguration}.class), @{@link ConditionalOnMissingBean}({@link PageableHandlerMethodArgumentResolver}.class))
 *
 * @see SpringDataWebAutoConfiguration#springDataWebSettings()
 * @see RepositoryRestMvcConfiguration#pageableResolver()
 */
@Configuration
@EnableConfigurationProperties(SpringDataWebProperties.class)
public class DataRestConfig {

    @Bean
    public SpringDataWebSettings springDataWebSettings(SpringDataWebProperties springDataWebProperties) {
        return new SpringDataWebSettings(springDataWebProperties.getPageable().getSerializationMode());
    }

}

zyro23 avatar Mar 07 '25 09:03 zyro23

This is causing problems on our project. Enabling @EnableSpringDataWebSupport prevents the app from starting just like OP shared, and removing the annotation causes a warning every time a controller handles a request:

2025-03-12T15:01:33.851+01:00  WARN 299232 --- [nio-8080-exec-9] ration$PageModule$WarningLoggingModifier : Serializing PageImpl instances as-is is not supported, meaning that there is no guarantee about the stability of the resulting JSON structure!
	For a stable JSON structure, please use Spring Data's PagedModel (globally via @EnableSpringDataWebSupport(pageSerializationMode = VIA_DTO))
	or Spring HATEOAS and Spring Data's PagedResourcesAssembler as documented in https://docs.spring.io/spring-data/commons/reference/repositories/core-extensions.html#core.web.pageables.

lutzseverino avatar Mar 12 '25 14:03 lutzseverino

Keeping spring-boot-starter-web and removing spring-boot-starter-data-rest solved the problem. I guess this is still a problem if you need the data rest package for whatever reason.

Edit: My team wrongfully set the spring-boot-starter-data-rest dependency explicitly, we didn't need it, though, as far as I know, it's already included by another library? It's slightly confusing to me as to why adding it explicitly raises this problem.

lutzseverino avatar Mar 12 '25 16:03 lutzseverino