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

Eclipse 4.12, Java 12 or 8, Gradle 5.6 or Maven 3.6.1, Tomcat 9.0.24

Creating Project

Create a gradle or maven based project in Eclipse. The project name is spring-service-layer-bean-validation.

We are going to deploy the war file into external Tomcat server in case of gradle based project.

Build File

You need to update build.gradle script or pom.xml file according to your project type.

We need validator dependency and validator provider dependency (such as Hibernate-Validator).

build.gradle

Include required dependencies in the build script for gradle based project as shown in the below file.

apply plugin: 'war'
apply plugin: 'java'
    
sourceCompatibility = 12
targetCompatibility = 12

repositories {
	mavenLocal()
    mavenCentral()
}

dependencies {
	implementation('org.springframework:spring-webmvc:5.1.9.RELEASE')
	implementation('javax.validation:validation-api:2.0.1.Final')
	providedCompile('javax.servlet:javax.servlet-api:4.0.1')
	implementation('org.hibernate.validator:hibernate-validator:6.0.17.Final')
	implementation('com.fasterxml.jackson.core:jackson-databind:2.10.0.pr2')
}

pom.xml

Add the required dependencies into the pom.xml file for maven based project as shown in the below file.

<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/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	
	<groupId>com.roytuts</groupId>
	<artifactId>spring-service-layer-bean-validation</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<failOnMissingWebXml>false</failOnMissingWebXml>
		<java-version>12</java-version>
		<spring.version>5.1.9.RELEASE</spring.version>
		<jackson.version>2.10.0.pr2</jackson.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>${jackson.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>4.0.1</version>
			<scope>provided</scope>
		</dependency>
		<!-- validator start -->
		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>2.0.1.Final</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>6.0.17.Final</version>
		</dependency>
		<!-- validator end -->
	</dependencies>
	<build>
		<finalName>${project.artifactId}</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
				<configuration>
					<source>${java-version}</source>
					<target>${java-version}</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Creating Config Class

We will use annotation based Spring MVC, so the below class will enable Spring MVC in our application.

We have also defined a Validator bean which will validate the input request.

package com.roytuts.spring.service.layer.bean.validation.config;

import javax.validation.Validator;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@EnableWebMvc
@Configuration
@ComponentScan(basePackages = "com.roytuts.spring.service.layer.bean.validation")
public class MvcConfig {

	@Bean
	public Validator validator() {
		return new LocalValidatorFactoryBean();
	}

}

@Configuration tells it is a configuration file; @EnableWebMvc tells it is Spring MVC; @ComponentScan looks for the annotated controllers, services classes in the respective packages.

Creating MVC Initializer Class

Create below class in order to initialize the configurations and Servlet mapping for Spring MVC.

If you are creating Spring Boot project then you don’t need this class.

package com.roytuts.spring.service.layer.bean.validation.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class MvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class[] { MvcConfig.class };
	}

	@Override
	protected Class<?>[] getServletConfigClasses() {
		return null;
	}

	@Override
	protected String[] getServletMappings() {
		return new String[] { "/" };
	}

}

Creating VO Class

Create below POJO class that will be act as an input to the REST API. We 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(“”).

Creating 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.

Creating REST Controller

Now create below Spring REST Controller class to expose the service to the client or end user so that we can test our 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/spring-service-layer-bean-validation/greet

Request Body:

{
        "name" : ""
}

or

{
        "name" : null
}

Response body:

HTTP Status 500 - Request processing failed; nested exception is javax.validation.ConstraintViolationException: Error occurred: Name is required field
type Exception report
message Request processing failed; nested exception is javax.validation.ConstraintViolationException: Error occurred: Name is required field
description The server encountered an internal error that prevented it from fulfilling this request.
exception
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.ConstraintViolationException: Error occurred: Name is required field
	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
	org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:648)

URL:http://localhost:8080/spring-service-layer-bean-validation/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.

Source Code

Thanks for reading.

Tags:

Leave a Reply

Your email address will not be published. Required fields are marked *