Catching JSON deserialization error on HTTP endpoint - java

I have a HTTP endpoint that receives and returns JSON content.
While testing for edge cases, I figured the endpoint returns the detailed content of the error when submitting a request with an unexpected JSON object.
In details, I expect a string and instead submit an object, e.g.:
I expect:
{
"myKey" : "someValue"
}
while I submit:
{
"myKey" : {}
}
When submitting that wrong content, what I expect my endpoint to return is:
a HTTP response with status code 400 and an empty content.
However, what I received was:
a HTTP response with status code 400 and the following content:
Can not deserialize instance of java.lang.String out of START_OBJECT token
at [Source: org.apache.catalina.connector.CoyoteInputStream#5bcfg1cc; line: 1, column: 11] (through reference chain: com.example.MyRequest["myKey"])
I am using the RestEasy framework for my servlets and the Jackson library to serialize/deserialize JSON. I have tried to use an ExceptionMapper, to configure exception catching in my web.xml file, but I can apparently cannot catch that error and return an empty HTTP response.
How do I catch errors of JSON deserialization on my HTTP endpoint with RestEasy?

I am using below mapper and is working
In place of e.getLocalizedMessage() can use your message
package com.test.rest.service;
import java.util.Date;
import java.util.TimeZone;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
#Provider
public class DefaultExceptionHandler implements ExceptionMapper<Exception> {
public DefaultExceptionHandler() {
super();
TimeZone.setDefault(TimeZone.getTimeZone("IST"));
}
#Override
public Response toResponse(Exception e) {
// For simplicity I am preparing error xml by hand.
// Ideally we should create an ErrorResponse class to hold the error info.
StringBuilder response = new StringBuilder("<response>");
response.append("<status>ERROR</status>");
response.append("<message>"+e.getLocalizedMessage() + "</message>");
response.append("<time>" + new Date().toString() + "</time>");
response.append("</response>");
return Response.serverError().entity(response.toString()).type(MediaType.APPLICATION_XML).build();
}
}
My method :
#GET
#Path("consumeJSON")
#Consumes(MediaType.APPLICATION_JSON)
public String consumeJSON(Map<String, String> outputMap) {
return outputMap.get("Hello");
}

Related

How to customize the 401 in quarkus oidc?

I want to customize the 401/403 status code when access token is invalid in headers. I have create an exception mapper given below :
import io.quarkus.security.AuthenticationFailedException;
import org.jose4j.json.internal.json_simple.JSONObject;
import javax.annotation.Priority;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
#Provider//register as JAXRS provider
#Priority(1)
public class UnAuthorizedExceptionMapper implements ExceptionMapper<AuthenticationFailedException> {
#Override
public Response toResponse(AuthenticationFailedException exception) {
System.out.println("I m here:"+exception);
JSONObject ob=new JSONObject();
ob.put("errorCode",401);
ob.put("msg","Invalid access token");
return Response.status(Response.Status.UNAUTHORIZED)
.entity(ob.toJSONString())
.build();
}
}
But when I execute my code then above exception mapper is not executed instead following log is appearing in the console :
io.qua.oid.run.OidcProvider: (vert.x-eventloop-thread-1) Token verification has failed: The JWT is no longer valid - claim value.
How can I customize 401/403 status code msg in quarkus oidc.

How to handle `jsonParseException` from Jackson parser in Java

This is my first time writing code in Java I m running in to JsonParseException when I send invalid json data in my request body. I know I have to catch this error at the point where json body is getting parsed I don't have any idea how it works in my code. It would be great if someone can explain me how to catch the error and send the 400 response instead of the 500 which is being thrown as Uncaught server error and also how the request body is getting parsed.
I m using JAXRS: 2.0.1 and jackson for Json parsing it seems. I also added an exceptionMapper to handle these exceptions but it doesn't seem to work.
//./src/main/java/com.test.rest/Routes.java
package.com.test.rest;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
public class Routes implements Xyz{
#POST
#Path("test")
#Consumes({MediaType.APPLICATION_JSON})
#Produces(MediaType.APPLICATION_JSON)
public Response testJson(#Context HttpHeaders headers, #HeaderParam("abc") String abc, TestRequest request){
if(abc == null){
return Response.status(Response.Status.BAD_REQUEST).entity("Invalid headers").build();
}else{
return Response.status(Response.Status.OK).entity(request.gettestData()).build();
}
}
}
./src/main/java/com.test.rest/TestRequest.java
package.com.test.rest;
public class TestRequest {
private String testData;
public TestRequest () {
}
public TestRequest(String testData){
setTestData(testData);
}
public String gettestData(){
return testData;
}
public void setTestData(String testData){
if(testData!=null){
testData = testData.toLowerCase();
}
this.testData =testData;
}
}
./src/main/java/com.test.rest/JsonParseExceptionMapper.java
package.com.test.rest;
import com.fasterxml.jackson.core.JsonParseException;
import javax.annotation.Priority;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.core.*;
#Provider
#Priority(1)
public class JsonParseExceptionMapper implements ExceptionMapper<JsonParseException> {
#Override
public Response toResponse(final JsonParseException exception) {
return Response.status(Response.Status.BAD_REQUEST)
.entity("Cannot parse JSON")
.type(MediaType.TEXT_PLAIN)
.build();
}
}
All the files are in same level and I m using gradle to build my code
this is my request body
{
"testData":
}
//com.fasterxml.jackson.core.JsonParseException: Unexpected character

Return error in JSON body from webapplicationexception

I am trying to put my error message inside the body of an WebApplicationException.
I get the status code in postman but the body remains empty.
I have tried to add a mapper like this
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
#Provider
public class UnexpectedExceptionMapper implements ExceptionMapper<Exception> {
private static final transient ObjectMapper MAPPER = new ObjectMapper();
#Override
public Response toResponse(final Exception exception) {
ResponseBuilder builder = Response.status(Status.INTERNAL_SERVER_ERROR)
.entity(defaultJSON(exception))
.type(MediaType.APPLICATION_JSON);
return builder.build();
}
private String defaultJSON(final Exception exception) {
ErrorInfo errorInfo = new ErrorInfo(exception.getMessage(), exception.getMessage());
try {
return MAPPER.writeValueAsString(errorInfo);
} catch (JsonProcessingException e) {
return "{\"message\":\"An internal error occurred\"}";
}
}
}
But postman still tells me the body remains empty when I throw the error.
throw new Exception("test")
Is there a better way and why isn't this working?
The status gets updated but no body is passed with info in it.
The reason I need this is because I want to pass along the error that I get from another endpoint that I am calling.
EDIT:
I am also trying a simple Response version
but when i throw an error the entity is ignored as well
Response.status(Response.Status.UNAUTHORIZED).entity("Does not work").build();
Response.status(Response.Status.SEE_OTHER).entity("Does work").build();
I am throwing it like this for testing atm.
#POST
#Path("/place/actionid/{nr}")
#Produces("application/json")
public Response getActionIdForPlaceAssetOrder(#PathParam("nr") #Valid String nr, #Valid Body body) throws Exception {
Response response = Response.status(Response.Status.UNAUTHORIZED).entity("Some message here").build();
return response;
The above code throws the status but ignores the message. like i said any error message gets ignored. Is this maybe a jetty issue?
At the moment i would just be happy if i can get any message passed to postman.

Receiving "Request Entity Cannot be Empty" from paramaterized RESTful GET operation

New to java programming and still learning. I've built a RESTful service and I'm trying to pass in a parameter for a GET routine and I'm getting back a state 400 saying that the "Request entity cannot be empty". When I call the non-parameterized GET, the data comes back just fine. I've stripped down all the functionality of the parameterized GET to just return a simple string and I'm still getting the same message. Searched all over and can't find anything that's very helpful.
Below is the code that I'm running for the service. The method "GetChildAllInfo" makes a call to a local mySQL instance and returns a list of objects; that one works just fine. The parameterized one returns nothing, not even an exception.
Any help would be tremendously appreciated. Even if it's a ridiculously simple solution like a syntax error that I may have missed. AND I'm willing to accept any other advice on what you see in the code as well. Thanks!
package allowanceManagerChild;
import java.util.Set;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.Produces;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PUT;
import javax.ws.rs.core.MediaType;
import com.google.gson.Gson;
#Path("allowanceManagerChild")
public class AllowanceManagerChild {
#Context
private UriInfo context;
/**
* Creates a new instance of AllowanceManagerChild
*/
public AllowanceManagerChild() {
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public String getJson() {
String response = "";
Set<Child> children = Child.GetAllChildInfo();
for (Child child : children){
Gson gson = new Gson();
String json = gson.toJson(child);
response = response + json;
}
return response;
}
#GET
#Path("/{childID}")
#Produces(MediaType.APPLICATION_JSON)
public String getJson(int childID) {
String response = "";
try{
// Set<Child> children = Child.GetChildInfo(id);
// for (Child child : children){
// Gson gson = new Gson();
// String json = gson.toJson(child);
// response = response + json;
// }
response = "Made it here"; //Integer.toString(childID);
}
catch(Exception e){
response = e.toString();
}
return response;
}
/**
* PUT method for updating or creating an instance of AllowanceManagerChild
* #param content representation for the resource
*/
#PUT
#Consumes(MediaType.APPLICATION_JSON)
public void putJson(String content) {
}
}
Adding the #PathParam annotation to the method parameter might help:
#GET
#Path("/{childID}")
#Produces(MediaType.APPLICATION_JSON)
public String getJson(#PathParam("childID") int childID) {
See the RESTful Web Services Developer's Guide for more details.

Error message in REST webservices

I am calling REST webservices from JSP using AJAX . Can you tell me the best way to send custom error message from REST webservice to JSP ?
Consider using HTTP response codes with (possibly) json response bodies to supply any required information so the client application can react accordingly.
Consider using the WebapplicationException. You can give it the Errorcode (also custom ones) and a body for the response. You could use the JSON Format if you have a complex structure to display your errors but i would suggest just using the an errormessage (for example in case of a bad request, what part of the request was bad).
If you are using JAX-RS REST webservice, you can configure Spring #Controller. Your method should produce application/json and return Response object, like in this example:
#GET
#Path("/get/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response getUserById(#PathParam("id") String userId) {
// Here your logic
Foo foo = new Foo();
foo.setMsg("Bad Request");
foo.setData("User " + userId + " not found")
return Response.status(400).entity(foo).build();
}
And from AJAX, you can catch error message
// Get user details
$.getJSON(encodeURI("./rest/user/get/" + userId), function(data) {
// Some logic on success
// Fail
}).fail( function(jqxhr) {
console.log(jqxhr.responseJSON.msg);
});
There are a couple of ways.
1. You can look at the response status you receive from the web service. The statuses starting with 2** are a success response (Eg: 200, 201), the ones starting with 4** or 5** are errors.
But the optimal way to handle and track exceptions is to use ExceptionMapper. You can write your own class that implements ExceptionMapper like below:
#Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {
#Override
public Response toResponse(Throwable arg0) {
return Response.status(Status.INTERNAL_SERVER_ERROR)
.entity("Custom Exception: Error retrieving data")
.build();
}
}
You can write your own custom exceptions like below or can throw blanket exception like below. The above approach is the preferred one though.
#Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {
#Override
public Response toResponse(Throwable arg0) {
return Response.status(Status.INTERNAL_SERVER_ERROR)
.entity("Custom Exception: Error retrieving data")
.build();
}
}

Categories

Resources