I have an ExceptionMapper called NotFoundExceptionMapper that I need to behave like this:
@Provider
public class NotFoundExceptionMapper implements
ExceptionMapper<NotFoundException> {
public Response toResponse(NotFoundException e) {
if(e originated from ClassA)
// create a complex ResponseTypeA and return it
if(e originated from ClassB)
// create a complex ResponseTypeB and return it
return DefaultResponseType;
}
}
The reason I need something like that is because in my REST layer, every method in class ClassA has essentially the exact same try & catch error handling, resulting in a lot of redundant code. The same goes for ClassB. The only difference between classA and ClassB is that methods in classA need to return a different Response type than the methods in classB.
The ExceptionMapper seems to be a great way to avoid redundant error handling code. The only thing left to do is decide where the exception comes from (ClassA or ClassB), perform some universal error handling and return the proper response type.
I have already working code for this, but I wonder if there's a more elegant way to do this. There are still a lot of things that I'm not familiar with in Jersey, so there's a good chance I missed something.
The code is fairly simple and uses UriInfo injection to discern where the exception comes from.
My ExceptionMapper:
@Provider
public class NotFoundExceptionMapper implements
ExceptionMapper<NotFoundException> {
@Context
UriInfo uriInfo;
public Response toResponse(NotFoundException e) {
// MyResponseBuilder decides which response type to return:
return MyResponseBuilder.buildResponse(uriInfo, e, Response.Status.NOT_FOUND);
}
}
The class MyResponseBuilder does all the magic. It analyzes the UriInfo and returns the proper response type.
public class MyResponseBuilder {
public static Response buildResponse(UriInfo uriInfo, Exception e, Status status) {
List<Object> matchedRes = uriInfo.getMatchedResources();
if(matchedRes.size() == 1) {
Object res = matchedRes.get(0);
if(res.getClass() == ClassA.class) {
ResponseTypeA resp = new ResponseTypeA();
// populate resp with infos
return Response.status(status).entity(resp).build();
}
else if(res.getClass() == ClassB.class) {
ResponseTypeB resp = new ResponseTypeB();
// populate resp with infos
return Response.status(status).entity(resp).build();
}
}
return Response.status(status).build(); // default response
}
}
And while it works, it may end up causing some nasty problems if there's more than one matched resource that operates on the same URI Edit: turns out the Jersey specification does not allow for one @Path to have multiple resources, so that situation shouldn't happen if handled properly (finding the correct resource, that is). Still, I don't find this to be a satisfying solution.
A more elegant way to the problem would be to somehow associate a NotFoundExceptionMapper_ThatReturnsResponseTypeA directly to ClassA, and another NotFoundExceptionMapper_ThatReturnsResponseTypeB to ClassB. I haven't found any way to do so, though.
Is there a way?