In enterprise applications we usually encounter situations where we get invalid request for our RESTful webservice. The processing fails but client doesn't know the exact cause of problem. In the below article I explain how can we handle invalid request by overriding the exception handling of a Jersey based RESTful webservice.
Jersey RESTful Web Services framework is open source, production quality, framework for developing RESTful Web Services in Java that provides support for JAX-RS APIs and serves as a JAX-RS (JSR 311 & JSR 339) Reference Implementation.
In web.xml, register "com.sun.jersey.spi.container.servlet.ServletContainer", and puts your Jersey service folder under init-param = "org.gv.blog"
We get an input which is not a valid json:
This will throw a JsonParseException. To handle this we can implement our own exception mapper.
This will throw an UnrecognizedPropertyException. To handle this we can implement our own exception mapper.
This will throw a JsonMappingException. To handle this we can implement our own exception mapper.
Jersey RESTful Web Services framework is open source, production quality, framework for developing RESTful Web Services in Java that provides support for JAX-RS APIs and serves as a JAX-RS (JSR 311 & JSR 339) Reference Implementation.
Implementation
web.xml
In web.xml, register "com.sun.jersey.spi.container.servlet.ServletContainer", and puts your Jersey service folder under init-param = "org.gv.blog"
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>org.gv.blog</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey-serlvet</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
MyRestService.java
REST service implementation
The RESTful webservice expects json input in below format
package org.gv.blog; @Path("/myService") public class MyRestService { @POST @Path("/sendContact") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.TEXT_PLAIN) public Response getMsg(Contact contact) { System.out.println("Contact is : " + contact.getName() + contact.getPhone() + contact.getEmail()); return "Contact accepted"; } }
The RESTful webservice expects json input in below format
{
"name": "Gaurav Varma",
"phone": 0009991122,
"email": "gaurav.yourfriend@gmail.com"
}
Contact.java
The input is mapped to a POJO as below.
public class Contact {
private String name;
private BigDecimal phone;
private String email;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getPhone() {
return phone;
}
public void setPhone(BigDecimal phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Problem Statement and Solution
Suppose we get an invalid request in input. As per default handling, jersey won't be able to read the request, fail with an exception and return HTTP 500 in response. The client would not be able to know what went wrong. To avoid this we can implement our own exception mapper and override jersey's exception handling.
Case 1. Invalid JSON format
We get an input which is not a valid json:{
"name": "Gaurav Varma", IamInvalid
"phone": 0009991122,
"email": "gaurav.yourfriend@gmail.com"
}
This will throw a JsonParseException. To handle this we can implement our own exception mapper.
@Provider
public class JsonParseExceptionMapper implements ExceptionMapper<JsonParseException>{
@Override
public Response toResponse(JsonParseException exception)
{
return Response
.status(Response.Status.BAD_REQUEST)
.entity("This is an invalid json. The request can not be parsed")
.type( MediaType.APPLICATION_JSON)
.build();
}
}
Case 2. Invalid attribute in request
We get an input which is a valid json but contains attribute which is not readable by the webservice:{
"nameInvalid": "Gaurav Varma",
"phone": 0009991122,
"email": "gaurav.yourfriend@gmail.com"
}
This will throw an UnrecognizedPropertyException. To handle this we can implement our own exception mapper.
@Provider
public class UnrecognizedPropertyExceptionMapper implements ExceptionMapper<UnrecognizedPropertyException>{
@Override
public Response toResponse(UnrecognizedPropertyException exception)
{
return Response
.status(Response.Status.BAD_REQUEST)
.entity("This is an invalid request. The field " + exception.getUnrecognizedPropertyName() + " is not recognized by the system.")
.type( MediaType.TEXT_PLAIN)
.build();
}
}
Case 3. Invalid attribute type in request
We get an input which is a valid json and contains attribute names expected by the webservice, but the type of attribute is not as expected.{
"name": "Gaurav Varma",
"phone": "I am not a number",
"email": "gaurav.yourfriend@gmail.com"
}
This will throw a JsonMappingException. To handle this we can implement our own exception mapper.
@Provider
public class JsonMappingExceptionMapper implements ExceptionMapper<JsonMappingException >{
@Override
public Response toResponse(JsonMappingException exception)
{
return Response
.status(Response.Status.BAD_REQUEST)
.entity("This is an invalid request. At least one field format is not readable by the system.")
.type( MediaType.TEXT_PLAIN)
.build();
}
}
This comment has been removed by the author.
ReplyDeleteNice!
ReplyDeleteThanks Sergio
DeleteHi Gaurav,
ReplyDeleteI really liked your simple and elegant solution for handling the exceptions. I am trying to implement your solution to handle exceptions in my application and I have made sure the exception mapper in the web.xml. Still the excpetion mapper doesn't kick-in when i supply wrong fields in JSON request body. I directly get a HTTP500 error with javax.servlet.ServletException: com.sun.jersey.api.container.MappableContainerException.
Do you have any suggestions on what i am missing? Any help will be highly appreciated.
com.sun.jersey.config.property.packages
mypackage.entires.here
Hi Raghunath,
ReplyDeleteDid you keep the exceptionMapper implementation in the same/child package as declared for jersey in web.xml? I yes, please send me the code and I can suggest further.
Thanks,
Gaurav
Thanks for sharing this informative information.You may also refer.....Exception handling in java An exception or exceptional event is a problem that arises during the execution of a program..
ReplyDeletehttp://www.s4techno.com/blog/2016/07/12/exception-handling/
This comment has been removed by a blog administrator.
ReplyDeleteThis beginner IPS Cloud Java tutorial describes fundamentals of programming in the Java ... Method references enable you to do this; they are compact, easy-to-read ...
ReplyDeleteYour article saved my time. Thank you Varma!
ReplyDeleteYou are welcome
DeleteHow to catch WebApplicationException ?
ReplyDeleteA similar handling to implement ExceptionMapper /WebApplicationException/ should handle that as well.
DeleteExcellent, that is what i needed, thanks so much
ReplyDeleteYou know your projects stand out of the herd. There is something special about them. It seems to me all of them are really brilliant!
ReplyDeleteshipping containers
I love the way you write and share your niche! Very interesting and different! Keep it coming!
ReplyDeleteshipping containers
How to handle following JSON Exception:
ReplyDeleteCaused by: javax.json.bind.JsonbException: Error deserialize JSON value into type: class java.lang.Integer.
HI. Here is two question. 1. When I add the exception mapper class inner the service class, it doesn't work. When I add the exception mapper class parallel to the service class, it works. Why did the previous situation fail? 2. If I should contains all of your above three cases, how can I merge the three exception mapper into one class?
ReplyDeleteThanks!
ReplyDeleteExcellent! Thank You Very Much :)
ReplyDelete