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.

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 !!