1. Overview

MessageSource is a powerful feature available in Spring applications. This helps application developers handle various complex scenarios with writing much extra code, such as environment-specific configuration, internationalization or configurable values.

One more scenario could be modifying the default validation messages to more user-friendly/custom messages.

In this tutorial, we’ll see how to configure and manage custom validation MessageSource in the application using Spring Boot.

2. Maven Dependencies

Let’s start with adding the necessary Maven dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

You can find the latest versions of these libraries over on Maven Central.

3. Custom Validation Message Example

Let’s consider a scenario where we have to develop an application that supports multiple languages. If the user doesn’t provide the correct details as input, we’d like to show error messages according to the user’s locale.

Let’s take an example of a Login form bean:

public class LoginForm {

    @NotEmpty(message = "{email.notempty}")
    @Email
    private String email;

    @NotNull
    private String password;

    // standard getter and setters
}

Here we’ve added validation constraints that verify if an email is not provided at all, or provided, but not following the standard email address style.

To show custom and locale-specific message, we can provide a placeholder as mentioned for the @NotEmpty annotation.

The email.notempty property will be resolved from a properties files by the MessageSource configuration.

4. Defining the MessageSource Bean

An application context delegates the message resolution to a bean with the exact name messageSource.

ReloadableResourceBundleMessageSource is the most common MessageSource implementation that resolves messages from resource bundles for different locales:

@Bean
public MessageSource messageSource() {
    ReloadableResourceBundleMessageSource messageSource
      = new ReloadableResourceBundleMessageSource();
    
    messageSource.setBasename("classpath:messages");
    messageSource.setDefaultEncoding("UTF-8");
    return messageSource;
}

Here, it’s important to provide the basename as locale-specific file names will be resolved based on the name provided.

5. Defining LocalValidatorFactoryBean

To use custom name messages in a properties file like we need to define a LocalValidatorFactoryBean and register the messageSource:

@Bean
public LocalValidatorFactoryBean getValidator() {
    LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
    bean.setValidationMessageSource(messageSource());
    return bean;
}

However, note that if we had already extended the WebMvcConfigurerAdapter, to avoid having the custom validator ignored, we’d have to set the validator by overriding the getValidator() method from the parent class.

Now we can define a property message like:

email.notempty=<Custom_Message>”

instead of

“javax.validation.constraints.NotEmpty.message=<Custom_message>”

6. Defining Property Files

The final step is to create a properties file in the src/main/resources directory with the name provided in the basename in step 4:

# messages.properties
email.notempty=Please provide valid email id.

Here we can take advantage of internationalization along with this. Let’s say we want to show messages for a French user in their language.

In this case, we have to add one more property file with the name the messages_fr.properties in the same location (No code changes required at all):

# messages_fr.properties
email.notempty=Veuillez fournir un identifiant de messagerie valide.

7. Conclusion

In this article, we covered how the default validation messages can be changed without modifying the code if the configuration is done properly beforehand.

We can also leverage the support of internationalization along with this to make the application more user-friendly.

As always, the full source code is available over on GitHub.