I'm in a little bit of bind... want my cake and to eat it too.
I want to log all exceptions my application throws. So if someone hits an incorrect URL, i want to log the stack trace to SLF4J.
So you're probably thinking, 'hey thats easy, just implement an exceptionmapper and log the exception." So I did:
public class RestExceptionMapper implements ExceptionMapper<java.lang.Exception> {
private static final Logger log = LoggerFactory.getLogger(RestExceptionMapper.class);
/**
* {@inheritDoc}
*/
@Override
public Response toResponse(Exception exception) {
log.error("toResponse() caught exception", exception);
return null;
}
}
If you do this, instead of 404 errors when someone types a wrong URL in, they get a 500 error. One would guess returning null would propagate the exception down the chain handlers, but Jersey doesn't do that. It actually provides very little info why it would choose one handler over another...
Has anyone ran into this problem and how did you solve it?
You can use a RequestEventListener to listen for an exception event and log the throwable, without interfering with any existing processing. Note that this means first registering an
ApplicationEventListener
which then returns an instance ofRequestEventListener
.To return the correct http status code, your exception mapper could look something like this:
Also it sounds like you are interested in cascading exception mappers, but according to the spec this isn't possible:
JAX-RS 2.0 Spec, Chapter 4.4
"Exception mapping providers map a checked or runtime exception to an instance of Response. An exception mapping provider implements the ExceptionMapper interface and may be annotated with @Provider for automatic discovery. When choosing an exception mapping provider to map an exception, an implementation MUST use the provider whose generic type is the nearest superclass of the exception.
When a resource class or provider method throws an exception for which there is an exception mapping provider, the matching provider is used to obtain a Response instance. The resulting Response is processed as if a web resource method had returned the Response, see Section 3.3.3. In particular, a mapped Response MUST be processed using the ContainerResponse filter chain defined in Chapter 6.
To avoid a potentially infinite loop, a single exception mapper must be used during the processing of a request and its corresponding response. JAX-RS implementations MUST NOT attempt to map exceptions thrown while processing a response previously mapped from an exception. Instead, this exception MUST be processed as described in steps 3 and 4 in Section 3.3.4."