Spring boot

Spring boot custom validator example

Creating Custom validation using spring

The method validation feature supported by Bean Validation 1.1 is automatically enabled as long as a JSR-303 implementation (such as Hibernate validator) is on the classpath.

This lets bean methods be annotated with javax.validation constraints on their parameters and/or on their return value.

Target classes with such annotated methods need to be annotated with the @Validated annotation at the type level for their methods to be searched for inline constraint annotations.

Create custom annotation (CommunicationType.java)

The below code shows you how to create a custom annotation to use with spring boot validation.

package com.candidjava.springboot.validators;

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
})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CommunicationTypeValidator.class)
@Documented
public @interface CommunicationType {
 String message() default "Communication preference must be email or mobile.";

 Class<?>[] groups() default {};

 Class<?extends Payload> [] payload() default {};
}

Custom logic using ConstraintValidator (CommunicationTypeValidator.java)

Defines the logic to validate a given constraint A for a given object type T.

Implementations must comply with the following restriction:

  • T must resolve to a non parameterized type
  • or generic parameters of T must be unbounded wildcard types
package com.candidjava.springboot.validators;

import java.util.Arrays;
import java.util.List;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class CommunicationTypeValidator implements ConstraintValidator< CommunicationType,String> {

 @Override
 public boolean isValid(String value, ConstraintValidatorContext context) {
  final List<String> commType = Arrays.asList("email", "mobile");
  return commType.contains(value);
 }

}

Using annotation with Entity class (Student.java)

Annotate the variable with created @CommunicationType annotation

package com.candidjava.springboot.models;

import javax.validation.constraints.NotEmpty;

import com.candidjava.springboot.validators.CommunicationType;

public class Student {
 private String id;
 @NotEmpty(message = "First name is required")
 private String name;
 private String age;
 @NotEmpty(message = "email is required")
 private String email;
 @NotEmpty(message = "mobile number is required")
 private String mobile;
 @NotEmpty(message = "Communication Type preference is required")
 @CommunicationType
 private String communicationType;

 public Student(String id, String name, String age, String email, String mobile, String communicationType) {
  this.id = id;
  this.name = name;
  this.age = age;
  this.email = email;
  this.mobile = mobile;
  this.communicationType = communicationType;
 }

 public String getCommunicationType() {
  return communicationType;
 }

 public void setCommunicationType(String communicationType) {
  this.communicationType = communicationType;
 }

 public String getName() {
  return name;
 }

 public String getEmail() {
  return email;
 }

 public void setEmail(String email) {
  this.email = email;
 }

 public String getMobile() {
  return mobile;
 }

 public void setMobile(String mobile) {
  this.mobile = mobile;
 }

 public void setName(String name) {
  this.name = name;
 }

 public String getId() {
  return id;
 }

 public void setId(String id) {
  this.id = id;
 }

 public String getAge() {
  return age;
 }

 public void setAge(String age) {
  this.age = age;
 }

}

Enabling Validation (StudentController.java)

Now use @Valid Annotation in method arguments to validate request object.

package com.candidjava.springboot.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import com.candidjava.springboot.models.Student;
import com.candidjava.springboot.service.StudentService;

@RestController
@RequestMapping(value = "/student")
public class StudentController {
 @Autowired
 StudentService service;

 @PostMapping("/create")
 public void create(@Valid @RequestBody Student student) {
  service.createStudent(student);
 }

 @GetMapping("/getAll")
 public List<Student> get() {
  return service.getAllStudents();
 }

 @GetMapping("/get/{id}")
 public Student getById(@PathVariable("id") String id) {
  return service.getStudentById(id);
 }

 @PutMapping("/update/{id}")
 public void update(@PathVariable("id") String id, @Valid @RequestBody Student student) {
  service.updateStudent(id, student);
 }

 @DeleteMapping("/delete/{id}")
 public void deleteById(@PathVariable("id") String id) {
  this.service.deleteStudentById(id);
 }

 @ResponseStatus(HttpStatus.BAD_REQUEST)
 @ExceptionHandler(MethodArgumentNotValidException.class)
 public Map<String,String> handleMethodArgumentNotValid(MethodArgumentNotValidException ex) {
  Map<String,String> errors = new HashMap<>();
  ex.getBindingResult().getFieldErrors()
   .forEach(error -> errors.put(error.getField(), error.getDefaultMessage()));
  return errors;
 }
}

Configure dependency (pom.xml)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.6.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.candidjava.spring.boot</groupId>
	<artifactId>validation</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>validation</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

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

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

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

Launch as Spring boot (Application.java)

package com.candidjava;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
 public static void main(String[] args) {
  SpringApplication.run(Application.class, args);
 }

}

Download

Download source code from my github account Click here