Handling custom error response in JAX-RS 2.0 client library Handling custom error response in JAX-RS 2.0 client library json json

Handling custom error response in JAX-RS 2.0 client library


I believe you want to do something like this:

Response response = builder.get( Response.class );if ( response.getStatusCode() != Response.Status.OK.getStatusCode() ) {    System.out.println( response.getStatusType() );    return null;}return response.readEntity( MyEntity.class );

Another thing you can try (since I don't know where this API puts stuff -- i.e. in the header or entity or what) is:

Response response = builder.get( Response.class );if ( response.getStatusCode() != Response.Status.OK.getStatusCode() ) {    // if they put the custom error stuff in the entity    System.out.println( response.readEntity( String.class ) );    return null;}return response.readEntity( MyEntity.class );

If you would like to generally map REST response codes to Java exception you can add a client filter to do that:

class ClientResponseLoggingFilter implements ClientResponseFilter {    @Override    public void filter(final ClientRequestContext reqCtx,                       final ClientResponseContext resCtx) throws IOException {        if ( resCtx.getStatus() == Response.Status.BAD_REQUEST.getStatusCode() ) {            throw new MyClientException( resCtx.getStatusInfo() );        }        ...

In the above filter you can create specific exceptions for each code or create one generic exception type that wraps the Response code and entity.


There are other ways to getting a custom error message to the Jersey client besides writing a custom filter. (although the filter is an excellent solution)

1) Pass error message in an HTTP header field.The detail error message could be in the JSON response and in an additional header field, such as "x-error-message".

The Server adds the HTTP error header.

ResponseBuilder rb = Response.status(respCode.getCode()).entity(resp);if (!StringUtils.isEmpty(errMsg)){    rb.header("x-error-message", errMsg);}return rb.build();

The Client catches the exception, NotFoundException in my case, and reads the response header.

try {    Integer accountId = 2222;    Client client = ClientBuilder.newClient();    WebTarget webTarget = client.target("http://localhost:8080/rest-jersey/rest");    webTarget = webTarget.path("/accounts/"+ accountId);    Invocation.Builder ib = webTarget.request(MediaType.APPLICATION_JSON);    Account resp = ib.get(new GenericType<Account>() {    });} catch (NotFoundException e) {    String errorMsg = e.getResponse().getHeaderString("x-error-message");    // do whatever ...    return;}

2) Another solution is to catch the exception and read the response content.

try {    // same as above ...} catch (NotFoundException e) {    String respString = e.getResponse().readEntity(String.class);    // you can convert to JSON or search for error message in String ...    return;} 


The class WebApplicationException was designed for that but for some reason it ignores and overwrites what you specify as parameter for the message.

For that reason I created my own extension WebAppException that honors the parameters. It is a single class and it doesn't require any response filter or a mapper.

I prefer exceptions than creating a Response as it can be thrown from anywhere while processing.

Simple usage:

throw new WebAppException(Status.BAD_REQUEST, "Field 'name' is missing.");

The class:

import javax.ws.rs.WebApplicationException;import javax.ws.rs.core.Response;import javax.ws.rs.core.Response.Status;import javax.ws.rs.core.Response.Status.Family;import javax.ws.rs.core.Response.StatusType;public class WebAppException extends WebApplicationException {    private static final long serialVersionUID = -9079411854450419091L;    public static class MyStatus implements StatusType {        final int statusCode;        final String reasonPhrase;        public MyStatus(int statusCode, String reasonPhrase) {            this.statusCode = statusCode;            this.reasonPhrase = reasonPhrase;        }        @Override        public int getStatusCode() {            return statusCode;        }        @Override        public Family getFamily() {            return Family.familyOf(statusCode);        }        @Override        public String getReasonPhrase() {            return reasonPhrase;        }    }    public WebAppException() {    }    public WebAppException(int status) {        super(status);    }    public WebAppException(Response response) {        super(response);    }    public WebAppException(Status status) {        super(status);    }    public WebAppException(String message, Response response) {        super(message, response);    }    public WebAppException(int status, String message) {        super(message, Response.status(new MyStatus(status, message)). build());    }    public WebAppException(Status status, String message) {        this(status.getStatusCode(), message);    }    public WebAppException(String message) {        this(500, message);    }}