3

I am working on Spring Boot, I have used Hibernate Validator to validate my beans. I have added a custom key with the @NotEmpty annotation, and add thos key/value pair in message.properties, but it's not getting its value from message.property

Here is my bean with validation annotation:

public class CategoryBean {
    @NotEmpty(message = "{category.name.notempty}")
    private String name;
    ----getter setter-----
}

message.properties (path:src/main/resources/message.properties)

category.name.notempty=Sorry! Category can't be empty

I have also configured message resource

@Bean
public MessageSource messageSource() {
    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    messageSource.setBasename("message");
    return messageSource;
}

I also configured LocalValidatorFactoryBean

@Bean
public LocalValidatorFactoryBean validator() {
    final LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
    localValidatorFactoryBean.setValidationMessageSource(messageSource());
    return localValidatorFactoryBean;
}

Whenever I am validating this bean, it's showing its key instead of its value. Hibernate validator default search message key inside ValidationMessages.properties so whenever I am adding ValidationMessages.properties file add there message this key value then it's working fine for me.

But I don't want to add ValidationMessage.properties file, instead of this I want to handle this message key in my message.properties file.

I know there are already some question related this in stack overflow, but those solutions are not solving my problem. I am unable to find out what I am doing wrong here.

Abdullah Khan
  • 12,010
  • 6
  • 65
  • 78
Bhushan Uniyal
  • 5,575
  • 2
  • 22
  • 45
  • Is the folder really called `reasources`? Because it should be `resources`. Also property files usually have extension `.properties` not `.property`. – Mark Rotteveel May 01 '17 at 10:51
  • @MarkRotteveel i am sorry, it was typo during the writing the description. I have update the description. – Bhushan Uniyal May 01 '17 at 11:49

3 Answers3

2

I can mistake with explonation, but I think that The main problem why you cannot resolve validation message key for NotEmpty with Spring MessageSource is Spring Boot auto configuration ValidationAutoConfiguration.

When you are using Spring Boot, it adds org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration where the defaultValidator component which looks something like this:

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ConditionalOnMissingBean(Validator.class)
public static LocalValidatorFactoryBean defaultValidator() {
    LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
    MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
    factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
    return factoryBean;
}

As you can see this factoryBean sets MessageInterpolator from MessageInterpolatorFactory using getObject() method which contains code:

return Validation.byDefaultProvider().configure()
                .getDefaultMessageInterpolator();

that returns default Hibernate org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator

Therefore Validator will use default Hibernate ResourceBundleMessageInterpolator to resolve validation message in ValidationMessages.properties file.

If you want to override default Hibernate ResourceBundleMessageInterpolator with own, you need put @Primary to your LocalValidatorFactoryBean:

@Bean
public MessageSource messageSource() {
    final ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    messageSource.setBasenames("classpath:messages");
    return messageSource;
}

@Bean
@Primary
public LocalValidatorFactoryBean validatorBean(MessageSource messageSource) {
    final LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
    bean.setValidationMessageSource(messageSource);
    return bean;
}

And then Validator will use your LocalValidatorFactoryBean with MessageSourceResourceBundleLocator to resolve validation messages in messages.propeties file.

jedicode
  • 145
  • 1
  • 11
  • If that's the case, is there a way to modify Spring Boot's provided `Validator` with `ValidationAutoConfiguration`? Why should we create a new one in the first place? My concern is regarding the rest of features provided for us via auto configuration, e.g. an advice and point cut by `MethodValidationPostProcessor` to trigger validation access strategy? Would the custom `@Primary Validator` created above be able to take advantage of those Spring Boot provided features? – Malvon Aug 18 '19 at 19:39
  • I think that all will work, because we create custom validator and Spring usually before wrap validator checks that we have one in application context and using this. For example you can see `WebMvcAutoConfiguration.EnableWebMvcConfiguration#mvcValidator` where spring before create new valiudator checks that we have one. What about `MethodValidationPostProcessor` it only uses bean that represent `Validator` class and it can be custom or default validator I think it doesn't matter for Spring. – jedicode Aug 19 '19 at 07:49
  • @Malvon I had exactly the same concern as you and came up with [this solution](https://github.com/spring-projects/spring-framework/issues/26149#issuecomment-734290699). – Hein Blöd Nov 26 '20 at 13:14
0

Give a try with this, replacing your MessageSource with this:

@Bean
public MessageSource messageSource() {
    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    messageSource.setBasenames("classpath:/messages");
    messageSource.setUseCodeAsDefaultMessage(false);
    messageSource.setCacheSeconds((int) TimeUnit.HOURS.toSeconds(1));
    messageSource.setFallbackToSystemLocale(false);
    return messageSource;
}

You have to put your message category.name.notempty=Sorry! Category can't be empty inside resources/messages.properties file

drenda
  • 5,846
  • 11
  • 68
  • 141
0

I've had the same problem. but I've solved now. My methods are simple.

  1. DO NOT USE @EnableWebMvc
  2. DO NOT EXTENDS org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport

Good luck.

greenb
  • 21
  • 3