JAX-RS (Jersey) custom exception with XML or JSON

I have a REST service built using Jersey.

I want to be able to set the MIME of my custom exception writers depending on the MIME that was sent to the server. application/json is returned when json is received, and application/xml when xml is received.

Now I hard code application/json, but that's making the XML clients left in the dark.

public class MyCustomException extends WebApplicationException {
     public MyCustomException(Status status, String message, String reason, int errorCode) {
         super(Response.status(status).
           entity(new ErrorResponseConverter(message, reason, errorCode)).
           type("application/json").build());
     }
}

What context can I tap into to get the current requests Content-Type?

Thanks!


Update based on answer

For anyone else interested in the complete solution:

public class MyCustomException extends RuntimeException {

    private String reason;
    private Status status;
    private int errorCode;

    public MyCustomException(String message, String reason, Status status, int errorCode) {
        super(message);
        this.reason = reason;
        this.status = status;
        this.errorCode = errorCode;
    }

    //Getters and setters
}

Together with an ExceptionMapper

@Provider
public class MyCustomExceptionMapper implements ExceptionMapper<MyCustomException> {

    @Context
    private HttpHeaders headers;

    public Response toResponse(MyCustomException e) {
        return Response.status(e.getStatus()).
                entity(new ErrorResponseConverter(e.getMessage(), e.getReason(), e.getErrorCode())).
                type(headers.getMediaType()).
                build();
    }
}

Where ErrorResponseConverter is a custom JAXB POJO


Solution 1:

You can try adding a @javax.ws.rs.core.Context javax.ws.rs.core.HttpHeaders field/property to your root resource class, resource method parameter, or to a custom javax.ws.rs.ext.ExceptionMapper and calling HttpHeaders.getMediaType().

Solution 2:

headers.getMediaType() responds with the media type of the Entity, not the Accept header. The appropriate way to convert the exception is with the Accept header so your client gets the response in the format they requested. Given the above solution, if your request looks like the following (note JSON accept header, but XML Entity), you will get XML back.

POST http://localhost:8080/service/giftcard/invoice?draft=true HTTP/1.1
Accept: application/json
Authorization: Basic dXNlcjp1c2Vy
Content-Type: application/xml
User-Agent: Jakarta Commons-HttpClient/3.1
Host: localhost:8080
Proxy-Connection: Keep-Alive
Content-Length: 502
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><sample><node1></node1></sample>

The correct implementation is again, to use the Accept header:

public Response toResponse(final CustomException e) {
    LOGGER.debug("Mapping CustomException with status + \"" + e.getStatus() + "\" and message: \"" + e.getMessage()
            + "\"");
    ResponseBuilder rb = Response.status(e.getStatus()).entity(
            new ErrorResponseConverter(e.getMessage(), e.getReason(), e.getErrorCode()));

    List<MediaType> accepts = headers.getAcceptableMediaTypes();
    if (accepts!=null && accepts.size() > 0) {
        //just pick the first one
        MediaType m = accepts.get(0);
        LOGGER.debug("Setting response type to " + m);
        rb = rb.type(m);
    }
    else {
        //if not specified, use the entity type
        rb = rb.type(headers.getMediaType()); // set the response type to the entity type.
    }
    return rb.build();
}