Introduction
In my previous tutorial I have shown how to validate input data coming from client or end user to Spring REST Controller. Now in this tutorial I will show you how to validate data in Spring Service Layer.
The reason behind validating input data in Service Layer is, input data from client may not always pass through the REST controller method and if you do not validate in Service layer also then unaccepted data may pass through the Service layer causing different issues.
Here I will use standard Java jsr-303
validation framework. I need to also use the validator provider, so here hibernate validator framework is used.
In this example, I will create Spring MVC project and you may also create Spring Boot and use the same code except the MvcInitializer
class and you need to add Spring Boot dependencies instead of Spring MVC.
Prerequisites
Java at least 8, Maven 3.6.1 – 3.6.3, Spring Boot 2.4.5
Project Setup
Create a maven based project in your favorite IDE or tool. The project name is spring-service-layer-bean-validation.
You need to update pom.xml file according to your project type. You need validator dependency and validator provider dependency (such as Hibernate-Validator).
Add the required dependencies into the pom.xml file for maven based project as shown in the below file.
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.roytuts</groupId>
<artifactId>spring-service-layer-bean-validation</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>12</maven.compiler.source>
<maven.compiler.target>12</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
VO Class
Create below POJO class that will be acting as an input to the REST API. I will pass this VO class in the request body of the REST call.
package com.roytuts.spring.service.layer.bean.validation.vo;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
public class User {
@NotEmpty(message = "Name is required field")
@NotNull(message = "Name is required field")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Here in the above class I have used two annotations @NotNull
and @NotEmpty
to make sure that name
attribute is neither null or empty(“”).
Spring Service Class
The corresponding service class that validates the input object is given in the below source code.
package com.roytuts.spring.service.layer.bean.validation.service;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Valid;
import javax.validation.Validator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.roytuts.spring.service.layer.bean.validation.vo.User;
@Service
public class GreetingService {
@Autowired
private Validator validator;
public String getGreetingMsg(@Valid User user) {
Set<ConstraintViolation<User>> violations = validator.validate(user);
if (!violations.isEmpty()) {
StringBuilder sb = new StringBuilder();
for (ConstraintViolation<User> constraintViolation : violations) {
sb.append(constraintViolation.getMessage());
}
throw new ConstraintViolationException("Error occurred: " + sb.toString(), violations);
}
return "Hi " + user.getName() + ", Good Morning!";
}
}
In the above class I have @Autowired
the validator bean defined in MvcConfig
class.
I have also used the @Valid
annotation in service method to make sure that input parameter is valid according to the specified constraint in the POJO class User
.
Spring REST Controller
Now create below Spring REST Controller class to expose the service to the client or end user so that you can test your application on input validation.
package com.roytuts.spring.service.layer.bean.validation.rest.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.roytuts.spring.service.layer.bean.validation.service.GreetingService;
import com.roytuts.spring.service.layer.bean.validation.vo.User;
@RestController
public class GreetingRestController {
@Autowired
private GreetingService service;
@PostMapping("/greet")
public Object getGreetingMsg(@RequestBody User user) {
return service.getGreetingMsg(user);
}
}
In the above REST controller method I have not used @Valid
annotation to avoid any validation here.
Testing the Application
Run the application in Tomcat server.
URL: http://localhost:8080/greet
Request Body:
{
"name" : ""
}
or
{
"name" : null
}
Response body:
{
"status": 500,
"error": "Internal Server Error",
"message": "",
"path": "/greet"
}
If you check the log then you will find the actual error as given below:
javax.validation.ConstraintViolationException: Error occurred: Name is required fieldName is required field
at com.roytuts.spring.service.layer.bean.validation.service.GreetingService.getGreetingMsg(GreetingService.java:30)
Now retest the service with the following data.
URL: http://localhost:8080/greet
Request Body:
{
"name" : "Soumitra"
}
Response Body:
Hi Soumitra, Good Morning!
That’s all. Hope you got an idea how to validate user input in service layer code.