1. Overview
One of the features of Java JSR 380 is allowing expressions while interpolating the validation messages with parameters.
When we use Hibernate Validator, there is a requirement that we need to add one of the uniform implementations of Java JSR 341 as a dependency to our project. JSR 341 is also called the Expression Language API.
However, adding an extra library can be cumbersome if we don't need to support parsing expressions according to our use-case.
In this short tutorial, we'll have a look at how to configure ParameterMessageInterpolator in Hibernate Validator.
2. Message Interpolators
Beyond the basics of validating a Java bean, the Bean Validation API's MessageInterpolator is an abstraction that gives us a way of performing simple interpolations without the hassle of parsing expressions.
Besides, Hibernate Validator offers a non-expression based ParameterMessageInterpolator, and therefore, we don't need any extra libraries to configure it.
3. Setting up Custom Message Interpolators
To remove the expression language dependency, we can use custom message interpolators and configure Hibernate Validator without expression support.
Let's show some of the convenient ways of setting up custom message interpolators. We'll use the built-in ParameterMessageInterpolator in our case.
3.1. Configuring ValidatorFactory
One way of setting up a custom message interpolator is to configure ValidatorFactory when bootstrapping.
Thus, we can build a ValidatorFactory instance with ParameterMessageInterpolator:
ValidatorFactory validatorFactory = Validation.byDefaultProvider() .configure() .messageInterpolator(new ParameterMessageInterpolator()) .buildValidatorFactory();
3.2. Configuring Validator
Similarly, we can set ParameterMessageInterpolator when we initialize the Validator instance:
Validator validator = validatorFactory.usingContext() .messageInterpolator(new ParameterMessageInterpolator()) .getValidator();
4. Performing Validations
To see how ParameterMessageInterpolator works, we need a sample Java bean with some JSR 380 annotations on it.
4.1. Sample Java Bean
Let's define our sample Java bean Person:
public class Person { @Size(min = 10, max = 100, message = "Name should be between {min} and {max} characters") private String name; @Min(value = 18, message = "Age should not be less than {value}") private int age; @Email(message = "Email address should be in a correct format: ${validatedValue}") private String email; // standard getters and setters }
4.2. Testing Message Parameters
Certainly, to perform our validations, we should use a Validator instance accessed from ValidatorFactory, which we already configured before.
So, we need to access our Validator:
Validator validator = validatorFactory.getValidator();
After that, we can write our test method for the name field:
@Test public void givenNameLengthLessThanMin_whenValidate_thenValidationFails() { Person person = new Person(); person.setName("John Doe"); person.setAge(18); Set<ConstraintViolation<Person>> violations = validator.validate(person); assertEquals(1, violations.size()); ConstraintViolation<Person> violation = violations.iterator().next(); assertEquals("Name should be between 10 and 100 characters", violation.getMessage()); }
The validation message is interpolated with variables of {min} and {max} correctly:
Name should be between 10 and 100 characters
Next, let's write a similar test for the age field:
@Test public void givenAgeIsLessThanMin_whenValidate_thenValidationFails() { Person person = new Person(); person.setName("John Stephaner Doe"); person.setAge(16); Set<ConstraintViolation<Person>> violations = validator.validate(person); assertEquals(1, violations.size()); ConstraintViolation<Person> violation = violations.iterator().next(); assertEquals("Age should not be less than 18", violation.getMessage()); }
Similarly, the validation message is interpolated correctly with the variable {value} as we expected:
Age should not be less than 18
4.3. Testing Expressions
To see how ParameterMessageInterpolator behaves with expressions, let's write another test for the email field that involves a simple ${validatedValue} expression:
@Test public void givenEmailIsMalformed_whenValidate_thenValidationFails() { Person person = new Person(); person.setName("John Stephaner Doe"); person.setAge(18); person.setEmail("johndoe.dev"); Set<ConstraintViolation<Person>> violations = validator.validate(person); assertEquals(1, violations.size()); ConstraintViolation<Person> violation = violations.iterator().next(); assertEquals("Email address should be in a correct format: ${validatedValue}", violation.getMessage()); }
This time, the expression ${validatedValue} is not interpolated.
ParameterMessageInterpolator only supports the interpolation of parameters, not parsing expressions that use the $ notation. Instead, it simply returns them un-interpolated.
5. Conclusion
In this article, we learned what ParameterMessageInterpolator is for and how to configure it in Hibernate Validator.
As always, all the examples involved in this tutorial are available over on GitHub.