In the previous Spring Boot Controller and Swagger, we have written implementation code for our swagger endpoints now we are going to see how we can validate parameters.
Since the client sends various parameters (header, query, path, request body) in request to our Rest API. we have to ensure that these parameters are valid before we can process the request and send the response.
To do that we don't have to write extra code instead we can use the bean validation in our project which contains pre-defined spring bean annotation to validation parameter.
Today we are going to learn how to use bean validation in our project.
Bean validation
Bean validation is validating the bean(Object) using some constraint annotation in fields, methods, classes. The bean Validator will check the declared constraint on the class whether or not constraint is satisfied if any constraint is not met then it triggers MethodArgumentNotValidException.
Spring boot will enable bean validation automatically if it finds any JSP implementation on the classpath.
Maven dependencies
Add below dependency for spring boot bean validation using hibernate Validator which is the most used bean validation.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Hibernate annotations
@Min and @Max ensure the numerical field is only valid when its value is above or below a certain value.
@min(0)
@Max(100)
private int mark;
@min(6)
@Max(6)
private int oTP;
@NotBlank is used to ensure the string value is not empty and should contain at least one character.
@NotBlank
private String name;
@NotNull check annotated field is not null.
@NotNull private GenderEnum gender;
@NotEmpty check annotated field or list is not empty nor null
@NotEmpty
private List<Employee> employees;
@Size(min=, max=) is used to ensure annotated element size is between min and max.
@Size(min=10,max=10)
private String mobileNo;
@Pattern(regex=) check the string against the given regular expression.
@Pattern(regex= "yyyy-MM-dd HH:mm")
private String joinedDate;
@Email check the string is valid mail address below annotation is used to do email validation and not empty on the variable.
@Email
@NotEmpty
private String yourMailId;
Validating Bean programmatically
By using the Validator class we can validate the object by passing the object to validate method in Validator which will check if constraints are satisfied.
package com.employee.example.util;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.employee.example.model.Employee;
@Component
public class RequestBodyValidator {
@Autowired
private Validator validator;
public boolean validRequestBody(Employee employee) {
Set constraintViolations = validator.validate(employee);
if (!constraintViolations.isEmpty()) {
throw new ConstraintViolationException(constraintViolations);
}
return true;
}
}
Validating Bean using annotation
we can validate the beans without using the Validator class just by @Validated and @Valid annotations.
@Validated is a class-level annotation that supports group validation, used to validate parameters passed to the methods of the class.
@Valid is used in method parameters that need to be validated.
public ResponseEntity addEmployee(@Valid @RequestBody Employee employeeDetails)
Creating Custom Validator
The @Target annotation is used to tell where this annotation is to be used e.g. field, parameter. If @Target is declared as a parameter it can use in the method parameter.
The @Retention annotation tells when the annotation must be available we will runtime so it will be available during JVM runtime.
@Constraint annotation tells the class which is going to validate our field and contains the validation logic. it's mentioned by validatedBy attribute.
By default, there will be 3 attributes inside the annotation they are the message(), payload(), and groups().
message() which contains the default message that will be used as an error message in case of an exception.
Creating Custom annotation
package com.employee.example.util;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
@Target({
ElementType.FIELD, ElementType.PARAMETER
})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ContainValueValidator.class)
@Documented
public @interface ContainValue {
String message() default "value is invalid";
Class<? > [] groups() default {};
Class<? extends Payload > [] payload() default {};
}
Creating Validator class
We have to create a class and implement the ConstraintValidator interface. This class contains the actual validation logic and override isValid() method.
The isValid() method contains the validation logic and returns a Boolean if the value passes the validation logic.
package com.employee.example.util;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.apache.commons.lang3.StringUtils;
public class ContainValueValidator implements ConstraintValidator {
@Override
public boolean isValid(String fieldValue, ConstraintValidatorContext validatorContext) {
return StringUtils.isNotBlank(fieldValue);
}
}
If you are facing the below error
javax.validation.ConstraintDeclarationException: HV000151: A method overriding another method must not redefine the parameter constraint configuration
It means you have added validation annotation on the subclass method parameters which is not there in superclass method parameters so you have to add the validation annotation on the superclass method.
Validating Request body
we have already added a few hibernate spring validation annotations on our request body so now test them by passing invalid values.
we have added @Size annotation to a mobile number to check its size is 10 and we have passed invalid value because its size is greater than 10 so our validation gets triggered and causes MethodArgumentNotValidException.
Validating Request parameter
let use our custom validation annotation created above in the header parameter(x-requestid) to check whether it's working fine.
if we don't pass any value in x-requestid then it triggers ConstraintViolationException.
view source code is available on gitHub.