Intro to JAX-RS Custom Validation

In this example, I will show the usage of ValidatorAdapter in association with @ValidateRequest annotation. For sending the request from UI, I will use ajax. You can use form submission if needed in your project. In that case, you will need @FormParam annotation to capture request parameters.

Below if the screenshot of functionality what we are going to acheive in this tutorial.

JAX-RS + Ajax  Validation example
JAX-RS + Ajax Validation example

Lets build this example tutorial step by step.

Step 1) Create a eclipse web project using maven

C:LokeshSetupworkspaceRESTfulValidation>mvn archetype:generate -DgroupId=com.howtodoinjava 
-DartifactId=RESTfulValidation -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

mvn eclipse:eclipse -Dwtpversion=2.0

Step 2) Update runtime dependencies in pom.xml file

<!-- core library -->
<dependency>
	<groupId>org.jboss.resteasy</groupId>
	 <artifactId>resteasy-jaxrs</artifactId>
	<version>2.3.1.GA</version>
</dependency>
<dependency>
	<groupId>net.sf.scannotation</groupId>
	<artifactId>scannotation</artifactId>
	<version>1.0.2</version>
</dependency>
<!-- JAXB provider -->
<dependency>
	<groupId>org.jboss.resteasy</groupId>
	<artifactId>resteasy-jaxb-provider</artifactId>
	<version>2.3.1.GA</version>
</dependency>

Step 3) Update web.xml with path mapping information

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <!-- Auto scan REST service -->
	<context-param>
		<param-name>resteasy.scan</param-name>
		<param-value>true</param-value>
	</context-param>
	
	<listener>
      <listener-class>
         org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
      </listener-class>
   </listener>
	
	<servlet>
		<servlet-name>resteasy-servlet</servlet-name>
		<servlet-class>
			org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
		</servlet-class>
	</servlet>
 
	<servlet-mapping>
		<servlet-name>resteasy-servlet</servlet-name>
		<url-pattern>/rest/*</url-pattern>
	</servlet-mapping>
</web-app>

Step 4) Create RESTful API on which validation will be performed

This API can have @ValidateRequest annotation at following levels:

  • Method level : It will enable the validation on that particular method.
  • Class level : It will enable the validation on all methods inside that class.

I am using this annotation at class level.

package com.howtodoinjava.rest;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

import org.jboss.resteasy.spi.validation.ValidateRequest;

@Path("/rest")
@ValidateRequest
public class UserService {
	
	
	@Path("/users")
	@POST
	public Response addUser(@QueryParam("firstName") String firstName, @QueryParam("lastName") String lastName)
	{
		System.out.println("User added !!");
		return Response.ok().build();
	}
}

Note: If you have used @ValidateRequest annotation at class level, and you want to disable validation on some APIs, you can use @DoNotValidateRequest annotation.

Step 5) Create your custom validator which will implement ValidatorAdapter class

Implemetation of ValidatorAdapter are automatically scanned by RESTEasy on start-up of application and registerd in context.

package com.howtodoinjava.validator;

import java.lang.reflect.Method;

import org.jboss.resteasy.spi.BadRequestException;
import org.jboss.resteasy.spi.validation.ValidatorAdapter;

public class CommonValidator implements ValidatorAdapter {

	@Override
	public void applyValidation(Object resource, Method invokedMethod, Object[] args) 
	{
		/*ValidateRequest classLevelValidateRequest = FindAnnotation.findAnnotation(invokedMethod.getDeclaringClass()
														.getAnnotations(), ValidateRequest.class);
		
		ValidateRequest methodLevelValidateRequest = FindAnnotation.findAnnotation(invokedMethod.getAnnotations(), ValidateRequest.class);
		
		boolean applyValidation = (classLevelValidateRequest != null || methodLevelValidateRequest != null);*/
		
		
		if( invokedMethod.getName().equalsIgnoreCase("addUser"))
		{
			if(args == null || args.length != 2)
			{
				throw new BadRequestException("Fill all fields");
			}
			
			if(((String) args[0]).isEmpty())
			{
				throw new BadRequestException("Fill first name");
			} 
			else if(((String) args[1]).isEmpty())
			{
				throw new BadRequestException("Fill last name");
			}
		}
	}

}

Step 6) Modify index.jap file to interact with REST API

This jsp file will contain HTML form with two input boxes. These text boxes will accept the first name and last name of user. We are trying to enable ajax powered validation functionality on this form.

<html>
<head>
<script lang="javascript">
	var xmlhttp;
	function postRequest(url, cfunc) {
		if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
			xmlhttp = new XMLHttpRequest();
		} else {// code for IE6, IE5
			xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
		}
		xmlhttp.onreadystatechange = cfunc;
		xmlhttp.open("POST", url, true);
		xmlhttp.send();
	}
	function submitForm() {
		postRequest(
				"./rest/users?firstName="+document.getElementById("firstName").value+"&lastName="+document.getElementById("lastName").value,
				function() {
					if (xmlhttp.readyState == 4 && xmlhttp.status != 200) {
						//alert(xmlhttp.responseText);
						document.getElementById("error").innerHTML = "<h2><span style='color:red'>Fill all fields !!</span></h2>";
					}
				});
	}
</script>
</head>
<body>
	<h1>JAX-RS Custom Validation</h1>
	<div id="error"></div>
	<form onclick="submitForm()" method="post">
		<p>
			First Name : <input type="text" name="firstName" id="firstName"/>
		</p>
		<p>
			LastName : <input type="text" name="lastName" id="lastName"/>
		</p>
		<input type="button" value="Add User" />
	</form>
	By :
	<b>http://www.howtodoinjava.com</b>
</body>
</html>

Step 7) Test the application

As soon as you try to submit emtry or half filled form, you get the validation error as shown in screen shot at start of post. Also, in server log you can verify the error logged as:

SEVERE: Failed executing POST /rest/users
org.jboss.resteasy.spi.BadRequestException: Fill first name
	at com.howtodoinjava.validator.CommonValidator.applyValidation(CommonValidator.java:30)
	at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:150)
	at org.jboss.resteasy.core.ResourceMethod.invokeOnTarget(ResourceMethod.java:257)
	at org.jboss.resteasy.core.ResourceMethod.invoke(ResourceMethod.java:222)
	at org.jboss.resteasy.core.ResourceMethod.invoke(ResourceMethod.java:211)
	at org.jboss.resteasy.core.SynchronousDispatcher.getResponse(SynchronousDispatcher.java:525)
	at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:502)
	at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:119)
	at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:208)
	at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:55)
	at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:50)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
Sourcecode Download

Happy Learning !!

 

Comments

Subscribe
Notify of
guest
4 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode