3

I am wondering what the proper use is for the Javax-RS/Jersey ExceptionMapper class when it comes to mapping WebApplicationExceptions

I like the following, simple, 3-status paradigm:

  • HTTP 200 OK indicates successful response, no errors at all whatsoever; and
  • HTTP 404 indicates client-side error; and
  • HTTP 500 indicates server-side error

The problem with WebApplicationExceptions is that they could either be client-side (403, Forbidden) or server-side (503 Bad Gateway); hence they might map to a 404 or 500 depending on the situation.

I'm struggling with trying to inspect WebApplicationException so that I can determine whether its client- or server-side.

My best attempt thus far:

// Groovy pseudo-code
class MyMapper implements ExceptionMapper<Throwable> {
    @Override
    Response toResponse(Throwable error) {
        if(error instanceof WebApplicationException) {
            if(isClientSide(error as WebApplicationException)) {
                // Return HTTP 404.
            } else {
                // Return HTTP 500.
            }
        } else if(error instanceof ClientException) {
            // Return HTTP 404.
        } else if(error instanceof ServerException) {
            // Return HTTP 500.
        } else {
            // All other throwables. Default to HTTP 500.
        }
    }

    private boolean isClientSide(WebApplicationException webAppExc) {
        // TODO: How to make this determination?
    }
}

So a few concerns/issues here:

  • Will this ExceptionMapper really catch all Throwables (every Exception and Error subclass), or just Throwables?; and
  • What can I do inside isClientSide(...) to determine whether the error thrown was client- or server-side in origin? Let's pretend that a WebApplicationException created with a status of FORBIDDEN should be considered "client-side", but one created with a status of BAD_GATEWAY should not be.
smeeb
  • 27,777
  • 57
  • 250
  • 447
  • 1
    I don't understand what you mean by client side error? 200, 404, 500 are errors generated from the server side. 404 which you said "indicates client side error" is a server side error thrown when the server doesn't FIND the requested resource. – M.. Sep 10 '15 at 09:28
  • Sure, thanks @Abhin (+1) let me clarify. **Yes**, all of these errors are sent back from the server to the client. When I say "*client-side error*", I mean that the request itself is bad. Perhaps the request failed authentication, or maybe the client is out of "API tokens" and isn't allowed to make the request until they purchase more. When I say "*server-side error*", I mean that the request itelf is valid/good, but some error on the server is preventing the server from responding to it. Does that make sense? – smeeb Sep 10 '15 at 10:17
  • Yes. Note that authentication failure; the request goes to server and fails; in "API tokens" example the request goes to server to check if they can purchase more; checks a condition and fails. Both requests go to server and fail; Webapplicationexception and mapper can be used to map these failures and generate a detailed response for them. Check my answer below. – M.. Sep 10 '15 at 12:53

1 Answers1

2

WebApplicationException and ExceptionMapper serve similar but slightly different purposes.

They both help the developer in setting a custom HTTP error code and response on occurence of specific exceptions.

WebApplicationException is mostly used for custom or user defined exceptions; which means whenever your application throws a user-defined exception you can set the HTTP response code that you want with a detailed description of what the problem is and also set the return type.

Looks something like this:-

public class UserDefinedExcpetion extends WebApplicationException {

  /**
  * Create a HTTP 404 Not Found Error as plain text
  * whenever a UserDefinedExcpetion happens.
  */
  public UserDefinedExcpetion (String yourMessage) {
    super(Response.status(Responses.NOT_FOUND).
    entity(yourMessage).type("text/plain").build());
  }
}

You use a ExceptionMapper on exceptions that already exist(for example ones not defined by the user) in your application and on occurance of these exceptions you want to send a custom HTTP error response with some details embedded; and setting the type of the message.

Use it like this:-

   @Provider
    public class IOExceptionMapper implements ExceptionMapper<java.io.IOException> {
      public Response toResponse(java.io.IOException) {
/** Mapper which maps to IOExcpetion and gets called automatically by the JAXRS runtime when this exception occurs. Throw a 404 when this exception occurs.**/
        return   Response.status(404).entity(ex.getMessage()).type("text/plain").build();
      }
    }

NOTE:- Note the @Provider annotation which registers this mapper in jaxrs runtime.

M..
  • 880
  • 7
  • 15
  • Ahhh thanks @Light (+1) - that makes sense. One quick followup if you don't mind: I understand that it is probably best practice *not* to implement an `ExceptionMapper`, but say I ignore that and create one anyways...will it be invoked any time *any* (including `WebApplicationExceptions`) throwables/errors/exceptions are thrown by the server? Thanks again! – smeeb Sep 10 '15 at 17:39
  • Hi.Yes. With the @Provider annotation you plug it into the jax rs runtime .So everytime that exception occurs your mapper will be called for you to customize the response. If you use the mapper on Throwable by definition it should map to all Errors and Exceptions occuring anytime; yes. – M.. Sep 10 '15 at 17:48
  • why would you want to extend WebApplicationException directly? This will have the side effect of container directly handling your exceptions plus the root exception class is far removed from your class. Just extend Exception and map it to a WebApplicationException in ThrowableMapper. – rjha94 May 29 '22 at 14:56