JAX-RS jersey ExceptionMappers User-Defined Exception

47,598

Solution 1

You need to annotate your exception mapper with @Provider, otherwise it will never get registered with the JAX-RS runtime.

@Provider
public class UserNotFoundMapper implements
        ExceptionMapper<UserNotFoundException> {
    @Override
    public Response toResponse(UserNotFoundException ex) {
        return Response.status(404).entity(ex.getMessage()).type("text/plain")
                .build();
    }
}

Solution 2

What I usually do when creating APIs is create my own exception that extends from RuntimeException so I don't necessarily have to catch my exception.

Here's an example:

NOTE: I'm using JAX-RS with Jersey

First: create my own Exception that extends from RuntimeException.

public class ExceptionName extends RuntimeException {

private int code;
private String message;

public int getCode(){
    return code;
}

public String getMessage(){
    return message;
}

public ExceptionName(int code, String message) {
    this.code = code;
    this.message = message;
}

}

Also implement a ExceptionMapper

@Provider
public class ExceptionName implements ExceptionMapper<ExceptionName>{

    @Override
    public Response toResponse(ExceptionName exception) {
        return Response.status(exception.getCode()).entity(exception.getMessage()).build();
    }

}

And every time that I want to throw an exception I just do it like this anywhere, the exception mapper will take care of returning a response to the client consuming the API

throw new ExceptionName(500,"there was an error with something here");
Share:
47,598
WhoAmI
Author by

WhoAmI

Playing with Play!

Updated on July 14, 2020

Comments

  • WhoAmI
    WhoAmI almost 4 years

    I am new to this, trying to achieve reading some docs but its not working, please bear with me.

    I have created a UserNotFoundMapper using ExceptionMappers like this:

    public class UserNotFoundMapper implements ExceptionMapper<UserNotFoundException> {
    
    @Override
    public Response toResponse(UserNotFoundException ex) {
        return Response.status(404).entity(ex.getMessage()).type("text/plain").build();
    }
    
    }
    

    This in my service:

    @GET
    @Path("/user")
    public Response getUser(@QueryParam("id") String id) throws UserNotFoundException{
        //Some user validation code with DB hit, if not found then
        throw new UserNotFoundException();
    }
    

    The UserNotFoundException is an User-Defined Exception.

    I tried this:

    public class UserNotFoundException extends Exception {
           //SOME block of code 
    }
    

    But when I invoke the service, the UserDefinedExceptionMapper is not getting invoked. It seems I might be missing something in the UserDefinedException. How to define this exception then?

    Please let me know how to define the UserNotFoundException.

  • Ryan Stewart
    Ryan Stewart about 11 years
    You don't invoke the mapper manually, and you wouldn't use Jersey-specific classes in your service layer. That's the whole point of mappers.
  • WhoAmI
    WhoAmI about 11 years
    Thanks for the reply. I need to know a few things related to this: Where lies the difference between using a WebApplicationException and using an ExceptionMapper? I am not sure under which circumstances which should be used :( Can you please provide your inputs on this?
  • WhoAmI
    WhoAmI about 11 years
    @RyanStewart Thanks for the inputs. I am new to this and trying to learn it. In teh above postedd code; if I remove the mapper invocation line with throw new UserNotFoundException(); then it is fine right? I cant understand what you meant by you wouldn't use Jersey-specific classes in your service layer. Can you please explain it in a bit details?
  • Perception
    Perception about 11 years
    @WhoAmI - web application exceptions are automatically mapped by the JAX-RS provider. So, as opposed to using exception mappers, for example, you could extend WebApplicationException and override it's getResponse method. Some people prefer to do this for all exceptions that they define solely for their JAX-RS implementation. Mappers are great though, for mapping exceptions that do not extend from WebApplicationException (e.g all the standard Java exceptions, exceptions from third party libraries etc etc).
  • WhoAmI
    WhoAmI about 11 years
    This statement: web application exceptions are automatically mapped by the JAX-RS provider I have seen it in a lot of docs I am reading around over the net. But not able to understand what actually it means in simple terms and what is the importance/usefulness of it :( Can you please explain?
  • Ryan Stewart
    Ryan Stewart about 11 years
    @WhoAmI: The Jersey User Guide lays it out pretty clearly, if not in great detail. It means that a WebApplicationException holds a Response inside it, and when you throw one of them, that Response is what gets returned to the user.
  • Ryan Stewart
    Ryan Stewart about 11 years
    @WhoAmI: Which exception approach to use is up to you. The strength of the ExceptionMapper is that your code can remain independent of Jersey, and you can also map exceptions that are beyond your control (framework exceptions). The strength of the WebApplicationException is that it's simpler to use.
  • WhoAmI
    WhoAmI about 11 years
    Ok so rather than returning a Response like we do in ExceptionMappers; we are supposed to use a super(Response.....) for the WebApplicationException. Thats all right?
  • Perception
    Perception about 11 years
    @ryanstewart - actually the mapping behavior for WebApplicationException is part of the JAX-RS specification, so it's portable across providers. Which is a great thing.
  • Ryan Stewart
    Ryan Stewart about 11 years
    @Perception: Good call. I often forget to make that distinction. s/Jersey/JAX-RS/ in my last comment!
  • gaoagong
    gaoagong about 4 years
    @WhoAmI The class you are in is called UserServiceImpl and is part of the service layer, not the controller layer. You don't want to force a particular implementation like jax-rs into the rest of your code. It's usage should be terminated at the controller layer. ExceptionMapper give you a way to handle exceptions via jersey without adding Response.status... throughout your code. Service layer code should only do business logic.