Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LocaleResolver (MVC) and LocaleContextResolver (WebFlux) beans will back off if a user provides a bean of the same type and a custom name but Framework will then use its own default #24209

Closed
wilkinsona opened this issue Nov 19, 2020 · 12 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@wilkinsona
Copy link
Member

wilkinsona commented Nov 19, 2020

While looking at #24207, I noticed that our overrides of the localeResolver() (MVC) and localeContextResolver() (WebFlux) methods will back off if any LocaleResolver or LocaleContextResolver bean is present (they're annotated with a plain @ConditionalOnMissingBean) but Framework consumes these beans using a specific name. This means that a user may provide a custom bean with a non-standard name and our auto-configuration will back off, but Framework will then use its default rather than the user's bean. If you're trying to figure out what's happened, the condition evaluation report won't help much as it'll show that the auto-configured resolver backed off in favour of the user-provided resolver but won't explain why the user-provided resolver wasn't used.

I am wondering if our auto-configured beans should only back off when a bean of the name that Framework looks for is defined:

@ConditionalOnMissingBean(name = WebHttpHandlerBuilder.LOCALE_CONTEXT_RESOLVER_BEAN_NAME)
@ConditionalOnMissingBean(name = DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)

This would make the condition evaluation report more useful as it will show that the auto-configured bean was configured as no bean with a specific name was found in the context.

@wilkinsona wilkinsona added the for: team-attention An issue we'd like other members of the team to review label Nov 19, 2020
@wilkinsona wilkinsona changed the title LocaleResolver (MVC) and LocaleContextResolver (WebFlux) beans will back off if a user provides a bean of the same type but Framework will then use its own default LocaleResolver (MVC) and LocaleContextResolver (WebFlux) beans will back off if a user provides a bean of the same type and a custom name but Framework will then use its own default Nov 19, 2020
@philwebb
Copy link
Member

I think we probably should. I'd even say this is a bug and should perhaps be fixed in 2.2.x

@wilkinsona wilkinsona changed the title LocaleResolver (MVC) and LocaleContextResolver (WebFlux) beans will back off if a user provides a bean of the same type and a custom name but Framework will then use its own default LocaleResolver bean will back off if a user provides a bean of the same type and a custom name but Framework will then use its own default Nov 20, 2020
@wilkinsona
Copy link
Member Author

The LocaleContextResolver problem is specific to 2.4.0. I'll fix the MVC side of things in 2.2.x and 2.3.x and both in 2.4.x.

@wilkinsona wilkinsona added type: bug A general bug and removed for: team-attention An issue we'd like other members of the team to review labels Nov 20, 2020
@wilkinsona wilkinsona added this to the 2.2.x milestone Nov 20, 2020
@wilkinsona
Copy link
Member Author

In 2.2 and 2.3 the auto-configured LocaleResolver is @ConditionalOnProperty(prefix = "spring.mvc", name = "locale"). For the problem described above to occur, you'd have to set the spring.mvc.locale property and provide a custom LocaleResolver bean that isn't named localeResolver(). I think that's sufficiently unlikely to happen that the risk of the fix isn't worth the marginal improvement.

In 2.4.0 things are different as both the LocaleResolver and LocaleContextResolver beans are not @ConditionalOnProperty.

@wilkinsona wilkinsona changed the title LocaleResolver bean will back off if a user provides a bean of the same type and a custom name but Framework will then use its own default LocaleResolver (MVC) and LocaleContextResolver (WebFlux) beans will back off if a user provides a bean of the same type and a custom name but Framework will then use its own default Nov 20, 2020
@wilkinsona wilkinsona modified the milestones: 2.2.x, 2.4.x Nov 20, 2020
@wilkinsona wilkinsona self-assigned this Nov 20, 2020
@wilkinsona wilkinsona modified the milestones: 2.4.x, 2.4.1 Nov 20, 2020
@theHilikus
Copy link

@wilkinsona we are having a regression related to localeResolver and i'm wondering if it's related to this ticket or an actual regression in Spring

We are using mvc and we localize our ui using thymeleaf. Since updating to 2.4.1 (tested with 2.4.0 and the problem is there. but it is NOT there in 2.3.7) our application doesn't start and gives the error

20:07.617  WARN 93032 --- [  restartedMain] gServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'localeResolver' defined in class path resource [com/foo/ui/config/UiConfig.class]: Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=uiConfig; factoryMethodName=localeResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/foo/ui/config/UiConfig.class]] for bean 'localeResolver': There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration; factoryMethodName=localeResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.class]] bound.

The error is misleading. I was able to find the conflicting bean in org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport, not in DelegatingWebMvcConfiguration like the error says. But in any case, shouldn't that bean back off when i register my own LocaleResolver?

I haven't been able to find official documentation to configure a localizationResolver. I just followed this article which instructs to create the bean like this

@Bean
public LocaleResolver localeResolver() {
    SessionLocaleResolver slr = new SessionLocaleResolver();
    slr.setDefaultLocale(Locale.US);
    return slr;
}

But again, such a bean collides with the one in WebMvcConfigurationSupport and if renamed it is not used by org.springframework.web.servlet.DispatcherServlet#initLocaleResolver, which does

this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);

I see that 2.3.X WebMvcConfigurationSupport doesn't create a localeResolver bean

Should I open a new ticket or am I missing something?

@philwebb
Copy link
Member

@theHilikus That sounds like a bug. The localeResolver in our EnableWebMvcConfiguration class is @ConditionalOnMissingBean so it should back off.

Could you check that you've not got an @EnableWebMvc annotation in your app? If you haven't, could we please have a new issue with a sample that shows the error.

@theHilikus
Copy link

ah. i did have @EnableWebMvc. Once i removed that, the problem was gone

Thank you for the info @philwebb

@snturk
Copy link

snturk commented Jul 17, 2023

I'm now dealing with the same problem as @theHilikus, without using @EnableWebMvc annotation, I get the following error when my application starts:

The bean 'localeResolver', defined in class path resource [path/to/MyConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class] and overriding is disabled.

However, I cannot override that bean without using spring.allow-bean-definition-overriding property set to true. It's not an okey solution for me.

@mychalvlcek
Copy link

@snturk have you found anything to this?

@snturk
Copy link

snturk commented Apr 12, 2024

@snturk have you found anything to this?

No, unfortunately.

@wilkinsona
Copy link
Member Author

@mychalvlcek @snturk In this case, Phil has already suggested what to do next:

Could you check that you've not got an @EnableWebMvc annotation in your app? If you haven't, could we please have a new issue with a sample that shows the error.

@mychalvlcek
Copy link

mychalvlcek commented Apr 13, 2024

dont have this annotation.. my setup is following, multi-module maven project, where multiple configuration classes implementing WebMvcConfigurer interface are used..

originally i've had direct usage of componentScan like following

@ComponentScan(basePackages = {
        "module1",
        "module2" // LocaleResolver bean is configured here
})

once I want to remove this component scan and switch just to autoconfiguration approach (module2 has autoconfiguration), it stops to work.. so I guess it is connected to order of execution of all configurations (especially those implementing WebMvcConfigurer where spring-configured LocaleResolver will be automatically created earlier)

@wilkinsona
Copy link
Member Author

wilkinsona commented Apr 13, 2024

Yes, it sounds like your auto-configuration is ordered incorrectly. The auto-configuration that defines your custom LocaleResolver bean must be ordered before WebMvcAutoConfiguration (which is @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)) otherwise WebMvcAutoConfiguration won't be able to see your LocaleResolver bean and it won't back off.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

5 participants