Reputation: 1945
What is the best way to return Jersey exceptions in JSON format? Here my sample code.
public static class CompoThngExceptionMapper implements ExceptionMapper<Exception> {
@Override
public Response toResponse(Exception exception) {
if (exception instanceof WebApplicationException) {
WebApplicationException e = (WebApplicationException) exception;
Response r = e.getResponse();
return Response.status(r.getStatus()).entity(**HERE JSON**).build();
} else {
return null;
}
}
Thanks in advance!!!
Upvotes: 7
Views: 13429
Reputation: 10400
Avoiding import Jackson classes but only stick to pure JAX-RS classes I create json exception wrappers like this.
Create ExceptionInfo wrapper and subclass various exception status types.
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@XmlRootElement
public class ExceptionInfo {
private int status;
private String msg, desc;
public ExceptionInfo(int status, String msg, String desc) {
this.status=status;
this.msg=msg;
this.desc=desc;
}
@XmlElement public int getStatus() { return status; }
@XmlElement public String getMessage() { return msg; }
@XmlElement public String getDescription() { return desc; }
}
- - - -
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.WebApplicationException;
/**
* Create 404 NOT FOUND exception
*/
public class NotFoundException extends WebApplicationException {
private static final long serialVersionUID = 1L;
public NotFoundException() {
this("Resource not found", null);
}
/**
* Create a HTTP 404 (Not Found) exception.
* @param message the String that is the entity of the 404 response.
*/
public NotFoundException(String msg, String desc) {
super(Response.status(Status.NOT_FOUND).entity(
new ExceptionInfo(Status.NOT_FOUND.getStatusCode(), msg, desc)
).type("application/json").build());
}
}
Then throw exceptions in a resource implementation and client receives a nice json formatted http error body.
@Path("/properties")
public class PropertyService {
...
@GET @Path("/{key}")
@Produces({"application/json;charset=UTF-8"})
public Property getProperty(@PathParam("key") String key) {
// 200=OK(json obj), 404=NotFound
Property bean = DBUtil.getProperty(key);
if (bean==null) throw new NotFoundException();
return bean;
}
...
}
- - - -
Content-Type: application/json
{"status":404,"message":"Resource not found","description":null}
Upvotes: 9
Reputation:
Depends on what you want to return, but personally I have an ErrorInfo
object that looks something like this:
public class ErrorInfo {
final transient String developerMessage;
final transient String userMessage;
// Getters/setters/initializer
}
which I pass around as part of my Exception
s, then I just use Jackson's ObjectMapper
to create a JSON string from the ErrorInfo
object in the ExceptionMapper
. The nice thing with this approach is that you can extend it very easily, so adding status information, time of error, whatever, is just a case of adding another field.
Bear in mind that adding in things like the response's status is a bit of a waste, as that will be coming back in the HTTP header anyway.
Update
A complete example as follows (in this case ErrorInfo has more fields in it, but you get the general idea):
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@Provider
public class UnexpectedExceptionMapper implements ExceptionMapper<Exception>
{
private static final transient ObjectMapper MAPPER = new ObjectMapper();
@Override
public Response toResponse(final Exception exception)
{
ResponseBuilder builder = Response.status(Status.BAD_REQUEST)
.entity(defaultJSON(exception))
.type(MediaType.APPLICATION_JSON);
return builder.build();
}
private String defaultJSON(final Exception exception)
{
ErrorInfo errorInfo = new ErrorInfo(null, exception.getMessage(), exception.getMessage(), (String)null);
try
{
return MAPPER.writeValueAsString(errorInfo);
}
catch (JsonProcessingException e)
{
return "{\"message\":\"An internal error occurred\"}";
}
}
}
Upvotes: 10