Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot validation message is not being resolved

I am having trouble getting my validation message to be resolved.

I have been searching and reading through the web and SO for some hours now, I want to relate the question with the marked answer of Customize spring validation error

I do have a MessageSource bean defined and the messages.properties it getting read correctly, as I also use it for regular text to be displayed with th:text="#{some.prop.name}, which does work absolutely fine. It is just the validation error that won't work the way it should. I'm sure it's a stupid mistake I just overlook... The validation itself works fine.

Constraint:

@NotEmpty(message="{validation.mail.notEmpty}")
@Email()
private String mail;

messages.properties:

# Validation
validation.mail.notEmpty=The mail must not be empty!

Template part:

<span th:if="${#fields.hasErrors('mail')}" th:errors="*{mail}"></span>

The displayed text:

{validation.mail.notEmpty}

I tried a lot of variation, all without success.

@NotEmpty(message="validation.mail.notEmpty")
@NotEmpty(message="#{validation.mail.notEmpty}")

Will just show the exact value of the messages string, no parsing.

<span th:if="${#fields.hasErrors('mail')}" th:errors="${mail}"></span>
<span th:if="${#fields.hasErrors('mail')}" th:errors="#{mail}"></span>
<span th:if="${#fields.hasErrors('mail')}" th:errors="#{*{mail}}"></span>
<span th:if="${#fields.hasErrors('mail')}" th:errors="#{__*{mail}__}"></span>

Will result in an error.


EDIT:

After debugging, I stumbled up on this:

Class: org.springframework.context.support.MessageSourceSupport

Method: formatMessage(String msg, Object[] args, Locale locale)

will be called with

formatMessage("{validation.mail.notEmpty}", null, locale /*German Locale*/)

And it will run into if (messageFormat == INVALID_MESSAGE_FORMAT) {

So... my message format is not correct. This is way out of my scope/knowledge. Anyone knows what that means?

like image 967
Korashen Avatar asked Aug 15 '17 11:08

Korashen


Video Answer


2 Answers

It looks like you are missing LocalValidatorFactoryBean definition in your application configuration. Below you can find an example of Application class that defines two beans: LocalValidatorFactoryBean and MessageSource that uses messages.properties file.

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.support.ReloadableResourceBundleMessageSource; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;  @SpringBootApplication public class Application {      @Bean     public MessageSource messageSource() {         ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();         messageSource.setBasename("classpath:messages");         messageSource.setDefaultEncoding("UTF-8");         return messageSource;     }      @Bean     public LocalValidatorFactoryBean validator() {         LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();         bean.setValidationMessageSource(messageSource());         return bean;     }      public static void main(String[] args) {         SpringApplication.run(Application.class, args);     } } 

Having LocalValidatorFactoryBean bean defined you can use custom validation message like:

@NotEmpty(message = "{validation.mail.notEmpty}") @Email private String email; 

and messages.properties:

validation.mail.notEmpty=E-mail cannot be empty! 

and Thymeleaf template file with:

<p th:if="${#fields.hasErrors('email')}" th:errors="*{email}">Name Error</p> 

Sample application

https://github.com/wololock/stackoverflow-answers/tree/master/45692179

I have prepared sample Spring Boot application that reflects your problem. Feel free to clone it and run it locally. It will display translated validation message if value posted with form does not meet @NotEmpty and @Email validation.

WebMvcConfigurerAdapter configuration

In case of extending WebMvcConfigurerAdapter you will have to provide validator by overriding getValidator() method from parent class, e.g.:

import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ReloadableResourceBundleMessageSource; import org.springframework.validation.Validator; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;  @Configuration @EnableWebMvc public class WebConfiguration extends WebMvcConfigurerAdapter {      @Bean     public MessageSource messageSource() {         ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();         messageSource.setBasename("classpath:messages");         messageSource.setDefaultEncoding("UTF-8");         return messageSource;     }      @Bean     @Override     public Validator getValidator() {         LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();         bean.setValidationMessageSource(messageSource());         return bean;     }      // other methods... } 

Otherwise if you define LocalValidatorFactoryBean bean in other place it will get overridden and there will be no effect.

I hope it helps.

like image 59
Szymon Stepniak Avatar answered Oct 03 '22 05:10

Szymon Stepniak


Not sure which version of spring boot you are using. I am using Spring boot 2.0.1.RELEASE. A clearer solution would be move all your validation messages to ValidationMessages.properties. This way you don't have to override the auto-configured Validator() and setting the MessageSource.

like image 34
want2learn Avatar answered Oct 03 '22 04:10

want2learn