Custom Validation across properties in a Class — SpringBoot

Nakul Pant
TechCret Software
Published in
3 min readApr 30, 2020

In SpringBoot we have been using all sorts of validation like @NotBlank, @NotEmpty, @Email, etc to use built in validations provided by the javax.validation.constraints package. But these are validations that are applied over a property in a class. What if we wanted our own validator that can validate a property based on the value of other properties.

Let's see how we can achieve this use case in spring boot by creating our own custom annotations for validations and use them in our application.

So let's start with our example. We will create a validator that validates our password and the confirm password from a command object and binds the error message if the validation fails.

I am using Lombok for some magic in my java class with @Data and @NoArgsConstructor. More on Lombok here. Next, you can see that am using a validation annotation with properties message —

@ConfirmPassword(message = “validation.student.password.match”)

This is a custom validation annotation that I have created to use my confirm password matching logic. This annotation will be working across the properties of StudentCO that is why we have annotated the class with the annotation, else we would have used it on the property if the validation was to be performed on a single property. Let’s dissect this annotation.

Here validatedBy = {ConfirmPasswordValidator.class} points to the class that will contain our main logic for validation. @Target is set to Element.TYPE since we want our annotation to be on class level. The default message when the validation will fail is set to the message which is Password and Confirm Password do not match.

Now, let's move to our validator class —

We now need to implement the ConstraintValidator which takes in the annotation ConfirmPassword and the class to validate which in our case is StudentCO. We need to override the isValid Method which will be triggered during the validation. If the return value is true for isValid then the validation passes else it fails.

Let’s check out the logic for the isPasswordConfirmPasswordMatched() method in studentService.

We check here if the password and confirm password fields are equal or not.

So far so good. Following the above steps, you will be able to create a custom validator of your own.

But the main catch comes here, you won’t be getting the validation failed messages by the getFieldErrors() method of the BindingResult instance. The reason being we didn’t validate a single field but we validated a class so this method won’t return you the validation failure message for the field. Let's see how do we get these messages.

For this, we will have to create a mapper that will extract the validation failure message from the binding result in global errors.

The validation messages generated by our custom validator can be found with the help of the getGlobalErrors() method in the BindingResult. In the fieldErrors, we identify the fields by getField() methods but in globalErrors we identify them by getCode() which contains the code, same as our annotation which is ConfirmPassword in our case.

The same procedure can be used with the model classes of our application as well.

--

--