Shaharyar Khan Shaharyar Khan -4 years ago 306
Java Question

How to handle error of wrong JSON data in Java Rest Web Service: Jackson JSON Parser Unrecognized token

this is my web service in which I am receiving JSON in student object.

@PUT
@Path("/{stuId}")
@Consumes({MediaType.APPLICATION_JSON})
public Response update( @PathParam("stuId") UUID stuUUID , Student updatedStudentInfo) {
return updateService.update(stuUUID, updatedStudentInfo);
}


and this is the student class:

public class Student{

private int id;
private String studentName;
private String Address;

@JsonProperty
public int getId() {
return id;
}
@JsonProperty
public void setId(int id) {
this.id = id;
}
@JsonProperty
public String getStudentName() {
return studentName;
}

.
.
.
.
}


It is working fine but I am not able to handle when scenario when I test it by sending erroneous JSON data. for example if I do it like this


curl -v 'https://localhost:9803/school/student/29374-345tr-44' -X PUT -H 'Accept: application/json, text/plain, /' -H 'My-API-Version: 1' -H 'Authorization: Basic' -H 'Content-Type: application/json;charset=utf-8' --data '{"studentName":"rock","Address":723868764}'


it geneartes an error:

Unrecognized token '723868764': was expecting ('true', 'false' or 'null')


Now how can I handle this situation that if some erroneous data comes then it should not send back any error or exception except the one which I want to send.



EDIT 1:



Below we can also see the exception which is being generated by Java code

Caused by: com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'sdfsdfdsfdsf': was expecting ('true', 'false' or 'null') at
[Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@5c6d324d; line: 1, column: 59]

Answer Source

I found two solutions available for this:
Solution 1: ExceptionMapper (jersey)

@Provider
public class ClientExceptionMapper implements ExceptionMapper<Throwable>
{
    @Override
    public Response toResponse(Throwable ex) 
    {

        return Response
                .status(Response.Status.BAD_REQUEST)
                .build();
    }
}

The important thing here is the anotation

@provider

I am not sure if it is necessary or not after using annotation to put scan configuration in web.xml but for the safe side, lets do it

<servlet>
    <servlet-name>my-servlet</servlet-name>
    <servlet-class>
        org.glassfish.jersey.servlet.ServletContainer
    </servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>
         com.myrootpackgae.ws;com.anotherPackage.errorHandling;
        </param-value>
    </init-param>
    <init-param>
        <param-name>jersey.config.server.provider.scanning.recursive</param-name>
        <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

your ExceptionMapper class should be in the same package of your Rest Service or under the Package hierarchy.
Last but not least, I used Throwable in my example but you can be specific to any Exception for instance

JsonParseException
JsonMappingException
UnrecognizedPropertyException etc ...



Solution 2: javax.ws.rs.container.ContainerResponseFilter

 public class MyRestAppResponseFilter implements ContainerResponseFilter {

        @Override
        public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
                throws IOException {

            // Remove StackTrace from all exceptions
            Object entity = responseContext.getEntity();
    if (entity instanceof Throwable) {
                responseContext.setEntity(null);
                responseContext.setStatus(Response.Status.BAD_REQUEST.getStatusCode());
 }           
            // TF-246 Prevent caching for privacy reasons
            responseContext.getHeaders().add("Cache-Control", "no-cache, no-store, must-revalidate");
            responseContext.getHeaders().add("Pragma", "no-cache");
            responseContext.getHeaders().add("Expires", "Thu, 01 Jan 1970 01:00:00 CET");

            // TF-752 Enable CORS for WkWebView
            responseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
        }
    }


An event listener for request is also available RequestEventListener which provides onEvent(RequestEvent) method.
I preferred to use solution #2

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download