ExceptionMapper not working as expected

2019-05-26 13:12发布

问题:

I am using jersey for REST web services.

I am handling all 404 responses by throwing NotFoundException(Package com.sun.jersey.api) whenever I don't get any object from service layer.

e.g.

@GET
@Path("/{folderID}")
@Produces(MediaType.APPLICATION_JSON)
public Response getFolder(@PathParam("folderID") int folderID) {
       .
       .
       .
       Folder folderObj = folderService.getFolder(folderID);
       if(folderObj == null){
            throw new NotFoundException("Folder with ID '"+folderID+"'  not found.");
       }
}

I have written ExceptionMapper for this exception.

@Provider
public class NotFoundExceptionMapper implements   ExceptionMapper<NotFoundException> {

public Response toResponse(NotFoundException ex) {
    ErrorMesage errorMessage = new ErrorMessage();
    errorMessage.setCode(Status.NOT_FOUND.getStatusCode());
    errorMessage.setMessage(ex.getMessage());

    return Response.status(Status.NOT_FOUND)
            .entity(errorMessage)
            .type(MediaType.APPLICATION_JSON)
            .build();
}

}

So When I give unknown folder ID as path parameter, exception is thrown but code in NotFoundExceptionMapper is not invoked. (I can see exception message in response but as 'plain text', even though in mapper I am returning response in JSON; and debug break point is also not hit).

Also, Above exception mapper is invoked when I enter incorrect resource name in URI, but not for incorrect path param.

I have also added exception mapper like below to respond to all other exceptions.

public class GenericExceptionMapper implements  ExceptionMapper<Throwable>{

public Response toResponse(Throwable ex) {
    ErrorMessage errorMessage = new ErrorMessage();
    errorMessage.setCode(Status.INTERNAL_SERVER_ERROR.getStatusCode());
    errorMessage.setMessage(ex.getMessage());


    return Response.status(errorMessage.getCode())
            .entity(errorMessage)
            .type(MediaType.APPLICATION_JSON)
            .build();   
}

Above code is called whenever any exception (other than mapped exceptions) is thrown and I get proper JSON response.

So what is wrong with NotFoundException here? I have googled about this and also looked into source of NotFoundException but didn't find anything useful, please guide me on this.

回答1:

A snippet from the jersey ServerRuntime class. It has a special logic that if the Exception is an instance of WebApplicationException and has a body, it does not go to the exception mappers at all.

private Response mapException(Throwable originalThrowable) throws Throwable {
    if (throwable instanceof WebApplicationException) {
        WebApplicationException webApplicationException = (WebApplicationException)throwable;
     }

    this.processingContext.routingContext().setMappedThrowable(throwable);
    waeResponse = webApplicationException.getResponse();
    if (waeResponse.hasEntity()) {
        LOGGER.log(java.util.logging.Level.FINE, LocalizationMessages.EXCEPTION_MAPPING_WAE_ENTITY(waeResponse.getStatus()), throwable);
        return waeResponse;
    }        

    long timestamp = this.tracingLogger.timestamp(ServerTraceEvent.EXCEPTION_MAPPING);
    ExceptionMapper mapper = this.runtime.exceptionMappers.findMapping(throwable);
}