Issue
I write a simple program to work with internationalization capabilities of Spring framework like the following:
@SpringBootApplication
public class Application {
@Bean
public LocaleResolver localeResolver(){
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(Locale.US);
return localeResolver;
}
@Bean
public MessageSource resourceBundleMessageSource(){
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setUseCodeAsDefaultMessage(true);
messageSource.setBasenames("message");
return messageSource;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
and my controller:
@RestController
public class MyController {
@Autowired
@Qualifier(value = "resourceBundleMessageSource")
private MessageSource messageSource;
@GetMapping(path = "/get")
public String getLocale(
@RequestHeader(value = "Accept-Language", required = false) Locale locale) {
return messageSource.getMessage("message.to.user",null, locale);
}
}
and I also created message.properties
, message_en.properties
and message_es.properties
in src/main/resources
folder.
my question is even though I have one instance of MessageSource
in my application context I have to use Qualifier(value = "resourceBundleMessageSource")
in order to get response from my controller other wise I get errors like this.
No message found under code 'message.to.user' for locale 'es'.
now I wonder why @Autowired
did not work according to expectations? i.e. autowire beans by type, and in this I have one bean of type MessageSource
Solution
Your question leaves out an important part and that is that you are using Spring Boot (although it can be inferred from the fact that you have a @SpringBootApplication
annotation main class, it isn't in the tags).
Spring Boot already configures a MessageSource
and does so under the name messageSource
(which is also the magic name used in Spring to determine the main MessageSource
to use).
You are adding an additional MessageSource
named resourceBundleMessageSource
.
With this you end up with 2 beans of the type MessageSource
. Now what Spring will do, as it cannot unique determine which one to use, it will take the name of the field (in your case messageSource
) and find one with the exact name (in this case the default one).
Actually it works as designed and documented, however you didn't realize there already was a MessageSource
pre-configured.
I would also suggest to use the default one, and remove your own MessageSource
definition. Instead add the following to the configuration
spring.messages.use-code-as-default-message=true
To achieve the behavior you have configured in your custom one.
In your controller you also don't need to get the Accept-Language
as that is what the SessionLocaleResolver
does, although you need to remove the defaultLocale
for this to work.
Answered By - M. Deinum