Spring 4 #PropertySource not working when ResourceBundleMessageSource bean is registered - spring

#Configuration
#PropertySource("classpath:service.properties")
public class ApplicationConfig{
#Value("PROPERTY_MYSQL_JNDI_NAME")
private String jndiName;
}
this was working fine. But when I register
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("resources/authentication");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
bean in the ApplicationConfig class previous property loading not working. is there any thing i can do to test it

I was facing the same issue. In my case, I had missed adding the following bean:
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
which made the property loading work correctly.

You messageSource is wrong it should be as below assuming your authentication.properties is in src/resources:
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("authentication");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
You can still use
#PropertySource("classpath:config.properties")
Assuming config.properties is in src/resources

Related

Why I'm getting org.springframework.context.NoSuchMessageException in spring boot?

I'm having properties/messages file name:
messages_en.properties
And I have the property inside:
country.AF.name=Afghanistan
here is the messages class:
#ApplicationScope
#Configuration
#Slf4j
public class Messages {
private ResourceBundleMessageSource messageSource;
private MessageSourceAccessor accessor;
#PostConstruct
private void init() {
messageSource();
accessor = new MessageSourceAccessor(messageSource, Locale.ENGLISH);
log.info("Messages initialized");
}
public String get(String code) {
return accessor.getMessage(code);
}
public void messageSource() {
messageSource = new ResourceBundleMessageSource();
messageSource.setBasenames("classpath:messages_en.properties");
messageSource.setUseCodeAsDefaultMessage(true);
}
The full error I'm getting is as follow:
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770) ~[jackson-databind-2.12.3.jar:2.12.3]
Postman show wrong results, I need to get all the countries:
Did you add the below things message Sources bean configuration
messageSource
.setBasename("classpath:messages_en.properties")

Spring Webflow: How to establish my own ReloadableResourceBundleMessageSource for a flow

Spring Webflow 2.5.1.
I have my own implementation of ReloadableResourceBundleMessageSource. I can successfully establish it in Spring MVC via:
#Bean
public ReloadableResourceBundleMessageSource messageSource() {
ReloadableResourceBundleMessageSource source = new AwareReloadableResourceBundleMessageSource();
source.setCacheSeconds(cacheSeconds);
source.setBasename("WEB-INF/i18n/messages");
source.setUseCodeAsDefaultMessage(true);
source.setDefaultEncoding("UTF-8");
return source;
}
My application uses both Spring MVC and Webflow.
I would like to have instances of the same AwareReloadableResourceBundleMessageSource in place for the individual per-flow messages.properties files.
I have tried:
#Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
...
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource ms = new AwareReloadableResourceBundleMessageSource();
ms.setBasename("messages");
System.out.println("MESSAGE SOURCE AwareReloadableResourceBundleMessageSource");
return ms;
}
}
But the messageSource() method is not called.
I have seen: https://stackoverflow.com/a/8126164
Any pointers/techniques/code snipppets very gratefully accepted.
Try the following:
Configure messageSource() within a ValidatorFactory bean, AND
Configure the ValidatorFactory bean within FlowBuilderServices
#Bean
public FlowBuilderServices flowBuilderServices() {
return getFlowBuilderServicesBuilder()
.setValidator(getValidator())
.build();
}
#Bean
public LocalValidatorFactoryBean getValidator() {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
bean.setValidationMessageSource(messageSource());
return bean;
}

Spring Boot, Hibernate validator language based on LocaleContextHolder

I've a Spring Boot 2.4.2 REST application using JPA, Hibernate, etc.
So far I use a MessageSource for applications errors (located in i18n/messages), and the default ValidationMessagesfor bean validations.
This is part of my configuration:
public static Set<Locale> LOCALES = Set.of(new Locale("en"), new Locale("it"));
#Bean
public LocaleResolver localeResolver() {
SmartLocaleResolver localeResolver = new SmartLocaleResolver();
return localeResolver;
}
public class SmartLocaleResolver extends AcceptHeaderLocaleResolver {
#Override
public Locale resolveLocale(HttpServletRequest request) {
if (StringUtils.isBlank(request.getHeader("Accept-Language"))) {
return Locale.getDefault();
}
List<Locale.LanguageRange> list = Locale.LanguageRange.parse(request.getHeader("Accept-Language"));
Locale locale = Locale.lookup(list, LOCALES);
return locale;
}
}
#Primary
#Bean("messageSource")
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setAlwaysUseMessageFormat(true);
messageSource.setBasenames("classpath:/i18n/messages");
// set to true only for debugging
messageSource.setUseCodeAsDefaultMessage(false);
messageSource.setFallbackToSystemLocale(false);
return messageSource;
}
My application supports 2 languages so far: it and en.
The problem right now is that application's messages are correctly localized in the agent's language (browser) but Validations errors are not.
I found out that Hibernate uses the default locale (Locale.getDefault()) and to customize the behaviour I should customize the locale resolution.
So I tried creating a custom hibernateValidator (that I set in my entityFactory) :
#Bean
public MessageSource validationMessageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setAlwaysUseMessageFormat(true);
messageSource.setBasenames("classpath:/ValidationMessages");
// set to true only for debugging
messageSource.setUseCodeAsDefaultMessage(false);
messageSource.setFallbackToSystemLocale(false);
return messageSource;
}
#Bean("hibernateValidator")
public LocalValidatorFactoryBean hibernateValidator() {
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
factoryBean.setValidationMessageSource(validationMessageSource());
return factoryBean;
}
and the resolver:
public class HibernateLocaleResolver implements LocaleResolver {
#Override
public Locale resolve(LocaleResolverContext context) {
return LocaleContextHolder.getLocale();
}
}
Doing this, the locale resolution works fine, but the parameter replacement doesn't. What I mean is for messages like this:
server.validators.ArraySize.message = The number of values must be between [{min}] and [{max}].
I've an exception:
"exception": "java.lang.IllegalArgumentException", "message": "can't parse argument number: min"
So I changed the configuration above adding the MessageInterpolator:
factoryBean.setMessageInterpolator(new ResourceBundleMessageInterpolator(LOCALES, Locale.ENGLISH, new HibernateLocaleResolver(), false));
At this point the parameters are resolved correctly, but again the locale resolution doesn't work.
Can you point me out in the right direction, trying to explain the best practice to follow for the combination Spring Boot - Hibernate Validator?
I solved the problem. I hope this can help someone else. This is my configuration file:
#Primary
#Bean("messageSource")
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setAlwaysUseMessageFormat(true);
messageSource.setBasenames("classpath:/i18n/messages");
// set to true only for debugging
messageSource.setUseCodeAsDefaultMessage(false);
messageSource.setFallbackToSystemLocale(false);
return messageSource;
}
#Bean
public MessageSource validationMessageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setAlwaysUseMessageFormat(true);
messageSource.setBasenames("classpath:/ValidationMessages");
// set to true only for debugging
messageSource.setUseCodeAsDefaultMessage(false);
messageSource.setFallbackToSystemLocale(false);
return messageSource;
}
#Bean
public LocalValidatorFactoryBean validator() {
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
factoryBean.setValidationMessageSource(validationMessageSource());
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
return factoryBean;
}
and the LocaleConfiguration:
#Configuration
public class LocaleConfiguration implements WebMvcConfigurer {
#Bean
public LocaleResolver localeResolver() {
SmartLocaleResolver localeResolver = new SmartLocaleResolver();
return localeResolver;
}
public class SmartLocaleResolver extends AcceptHeaderLocaleResolver {
#Override
public Locale resolveLocale(HttpServletRequest request) {
if (StringUtils.isBlank(request.getHeader("Accept-Language"))) {
return Locale.getDefault();
}
List<Locale.LanguageRange> list = Locale.LanguageRange.parse(request.getHeader("Accept-Language"));
Locale locale = Locale.lookup(list, Constants.LOCALES);
return locale;
}
}
}
the important part I saw made the difference are these lines:
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
In this way the interpolator works fine as well as the localization of the message.

Spring boot properties that depend on other properties

Do we have anyway where we can define one property is dependent on the other property?
messages.properties
product.name=XYZ
product.title=XYZ title
I have already tried the below one but its not working
product.name=XYZ
product.title=${product.name} title
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource =
new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
#Component
public class Messages {
#Autowired
private MessageSource messageSource;
private MessageSourceAccessor accessor;
#PostConstruct
private void init() {
accessor = new MessageSourceAccessor(messageSource);
}
public String get(String code, #Nullable Object[] args) {
return accessor.getMessage(code, args);
}
public String get(String code) {
return accessor.getMessage(code);
}
}

Spring 4 & Hibernate 5 validator messageSource does not work

I can't get use to work hibernate validation 5.1.0.Final with Spring MVC 4.2.5.RELEASE.
My WebConfig:
#Bean
public LocalValidatorFactoryBean validator() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(messageSource());
return validator;
}
#Bean
#Autowired
public MethodValidationPostProcessor getValidationPostProcessor(LocalValidatorFactoryBean validator) {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
processor.setValidator(validator);
return processor;
}
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("i18n/messages");
messageSource.setDefaultEncoding("UTF-8");
messageSource.setUseCodeAsDefaultMessage(true);
return messageSource;
}
#Override
public Validator getValidator() {
return validator();
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor(){
LocaleChangeInterceptor l = new LocaleChangeInterceptor();
l.setParamName("lang");
return l;
}
#Bean
public SessionLocaleResolver localeResolver(){
SessionLocaleResolver s = new SessionLocaleResolver();
s.setDefaultLocale(Locale.ENGLISH);
return s;
}
I have an ExceptionHanlder which gets validation messages and push it back as a json:
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
#ExceptionHandler(ConstraintViolationException.class)
#ResponseBody
public ValidationError handleConstraintViolation(final ConstraintViolationException exception) {
ValidationError v = new ValidationError();
exception.getConstraintViolations().forEach(violation -> {
v.addError(violation.getPropertyPath().toString(), violation.getMessage());
});
logger.warn(exception, exception);
return v;
}
I have 3 files in src/main/resources/i18n/: messages_en_EN.properties, messages_pl_PL.properties, messages.properties.
My model class with validation has one validated parameter:
#Column(name = "VALUE_", nullable = false)
#Email(message = "{Email.contractorContactEmail.value}")
#NotNull(message = "{NotNull.contractorContactEmail.value}")
private String value;
What I see is that hibernate validator look into classpath:ValidationMessages properties not into my spring message source. It may be ok for me but Hibernate does not want to translate those messages - locale is always server default. What am I doing wrong?? How can I fix it?
PS. In controller I use #org.springframework.validation.annotation.Validated.
PS2. I am sure that my messageSource is working correctly because if I add this code into ExceptionHandler it translates perfectly but I know that it is bad practice.
exception.getConstraintViolations().forEach(violation -> {
String messageTemplate = violation.getMessageTemplate();
if (messageTemplate.startsWith("{") && messageTemplate.endsWith("}")) {
String key = StringUtils.substring(messageTemplate, 1, messageTemplate.length() - 1);
v.addError(violation.getPropertyPath().toString(), messageSource.getMessage(key, null, LocaleContextHolder.getLocale()));
}
});
What I can tell you right away, judging from your configuration, your messages are in the wrong place - you've configured the message source to look at i18/messages but your messages are in the classpath root. So, your message source definition should look like:
#Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
messageSource.setDefaultEncoding("UTF-8");
messageSource.setUseCodeAsDefaultMessage(true);
return messageSource;
}
Aside from that, the rest of the configuration looks pretty much okay. I'm guessing that you're using the WebMvcConfigurerAdapter class?
EDIT:
For future reader's reference, the issue was not configuration-related, JPA entity was missing a #Valid annotation on a #OneToMany field so controller-level validation failed to pick it up and Hibernate's JPA validator used default messages.

Resources