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();
}