BAE
BAE

Reputation: 8936

how to map JSON parsing related errors to json response in jersey

I defined a datatype and its API:

public class DataType {
    @Column
    private String name;
}

// API is:
public class DataTypeAPI {
    @POST
    @Path("/")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    @ManagedAsync
    public void createDataType(
            final DataType dataType,
    ) {
        ...
        asyncResponse.resume(Response.status(Response.Status.CREATED)
                .entity(dataType)
                .build());
    }
}

Everything is fine if I posed { "name": "xxx" },

but when I posted { "name1": "xxx" }, I got the following text/plain response:

Unrecognized field "name1" (class com.xxx.datatypes.DataType), not marked as ignorable (1 known properties: "name"])
 at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@526e34b1; line: 2, column: 15] (through reference chain: com.xxx.datatypes.DataType["name1"])

I prefer to convert the above error into JSON response. but event I added the following exception mapper, it is not returning JSON response.

@Provider

public class GenericExceptionMapper implements ExceptionMapper<Throwable> {
    public Response toResponse(Throwable ex) {
        System.out.println("GenericExceptionMapper");
        ex.printStackTrace();
        return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                .entity(new ErrorBody(500, ex.getMessage()))
                .type(MediaType.APPLICATION_JSON)
                .build();
    }
}

Why my above exception mapper cannot catch the jersey parsing error. Could someone explain it to me? Thanks

UPDATE

I have two questions:

1, how to make the response to be application/json instead of text/plain?

2, why my exception mapper did not catch the exception raised and map it to a json response?

UPDATE

I added the following mapper:

public class JsonMappingExceptionMapper implements ExceptionMapper<JsonMappingException> {
    public Response toResponse(JsonMappingException ex) {
        return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                .entity(new ErrorBody(500, ex.getMessage()))
                .type(MediaType.APPLICATION_JSON)
                .build();
    }
}

Now, I can get the json response: { "code": 500, "message": "Unrecognized field \"name1\" (class com.xxx.datatypes.DataType), not marked as ignorable (1 known properties: \"name\"])\n at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@1d8cd12a; line: 2, column: 15] (through reference chain: class com.xxx.datatypes.DataType[\"name1\"])" }

I still have two questions:

1, why my generic exception mapper cannot catch it.

2, The json mapping exception mapper cannot map the following exception Unexpected character ('}' (code 125)): was expecting double-quote to start field name at [Source: org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream@7615743c; line: 3, column: 2] when {"name": "xxxx",}posted (comma , added for testing)

Upvotes: 7

Views: 9655

Answers (4)

Asaf Magen
Asaf Magen

Reputation: 1104

Im using org.glassfish.jersey-jackson-2.33. when you register JacksonFeature which is responsible for the default Jackson response with a "withoutExceptionMappers())". then if you have some Throwable exception mapper it will be catch instead of the default jackson mapper. you can also write your JsonParseException mapper if you dont use a Throwable mapper.

import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ResourceConfig;

public class JerseyApplication extends ResourceConfig {
    //register(JacksonFeature.class);
    register(JacksonFeature.withoutExceptionMappers());
}

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

import com.fasterxml.jackson.core.JsonParseException;

@Provider
public class JsonExceptionsMapper implements ExceptionMapper<JsonParseException> {
    @Override
    public Response toResponse(JsonParseException exception) {
         //replace with your custom response
         return Response.status(Response.Status.BAD_REQUEST).entity(exception.getMessage()).type("text/plain").build();
    }
}

Upvotes: 0

NiYanchun
NiYanchun

Reputation: 793

I met the same issue, and I have solved it. I try to explain your question:

Both JsonMappingException and JsonParseException extend JsonProcessingException. And Jersey has defined JsonMappingExceptionMapper for JsonMappingException and JsonParseExceptionMapper for JsonParseException.

  1. If you define your own mapper for JsonProcessingException (or more wide exception mapper), it cannot catch JsonMappingException and JsonParseException, because these two exceptions have their own mapper. If they have not, your mapper can catch.
  2. If you define your own mapper(say XxxJsonMappingExceptionMapper for JsonMappingException and YyyJsonParseExceptionMapper for JsonParseException), you may find sometimes you can catch these exceptions, sometimes cannot, it depends your own mapper is working or jersey's mapper is working. Now, you can add @Priority(1)(javax.annotation.Priority) to your mapper to make sure your mapper is working. see Jackson JsonParseExceptionMapper and JsonMappingExceptionMapper shadows custom mapper.

back to your question:

  1. Your generic exception mapper cannot catch it becasuse these exceptions has their own exception mapper(JsonMappingExceptionMapper and JsonParseExceptionMapper, they have a higher priority).
  2. You cannot catch the exception may because your own mapper is shadowed by the JsonParseExceptionMapper. Try to figure out by adding @Priority(1) to your own mapper

Upvotes: 5

Paul Samsotha
Paul Samsotha

Reputation: 208984

why my generic exception mapper cannot catch it.

Because the Jackson-JAXRS module already comes with ExceptionMappers for Jackson exceptions.

The json mapping exception mapper cannot map the following exception

I didn't test this, but it most likely because it is not a mapping exception, but a parsing exception. Jackson has both JsonParseException and JsonMappingException. You can see in the previous link that Jackson comes with an ExceptionMapper for both JsonMappingException and JsonParseException. You are only overriding the mapper for JsonMappingException.

Upvotes: 1

Ravi
Ravi

Reputation: 31397

Unrecognized field "name1" (class com.xxx.datatypes.DataType), not marked as ignorable (1 known properties: "name"])

If you look at the exception raised, it is quite clear that, your POJO class has property with name name not name1.

And, you are trying to post your JSON with property name name1.

{ "name1": "xxx" }

And, it wasn't recognized as name1 wasn't defined instead name.

public class DataType {
    @Column
    private String name;
}

And that is the reason , it works fine for you in other case, when you post JSON as

{ "name": "xxx" }

Upvotes: 0

Related Questions