Пусть ExceptionMapper возвращает разные типы ответов в зависимости от того, откуда происходит исключение
У меня есть ExceptionMapper с именем NotFoundExceptionMapper, который мне нужно вести себя так:
@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;
}
}
Причина, по которой мне нужно что-то подобное, заключается в том, что на моем уровне REST каждый метод в классе ClassA по сути одинаково обрабатывает ошибки try & catch, что приводит к большому количеству избыточного кода. То же самое относится и к ClassB. Единственная разница между classA и ClassB состоит в том, что методы в classA должны возвращать тип ответа, отличный от методов в classB.
ExceptionMapper, кажется, отличный способ избежать избыточного кода обработки ошибок. Осталось только решить, откуда возникло исключение (ClassA или ClassB), выполнить универсальную обработку ошибок и вернуть правильный тип ответа.
У меня уже есть код для этого, но мне интересно, есть ли более элегантный способ сделать это. В Джерси есть еще много вещей, с которыми я не знаком, так что есть большая вероятность, что я что-то пропустил.
Код довольно прост и использует инъекцию UriInfo, чтобы определить, откуда возникло исключение.
Мой 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);
}
}
Класс MyResponseBuilder делает всю магию. Он анализирует UriInfo и возвращает правильный тип ответа.
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
}
}
И хотя это работает, это может в конечном итоге вызвать некоторые неприятные проблемы, если существует более одного сопоставленного ресурса, работающего с одним и тем же редактированием URI: выясняется, что спецификация Джерси не позволяет одному @Path иметь несколько ресурсов, поэтому ситуация не должна это произойдет, если обработано правильно (то есть найти правильный ресурс). Тем не менее, я не считаю это удовлетворительным решением.
Более элегантный способ решения этой проблемы заключается в том, чтобы каким-либо образом связать NotFoundExceptionMapper_ThatReturnsResponseTypeA непосредственно с ClassA, а другой NotFoundExceptionMapper_ThatReturnsResponseTypeB - с ClassB. Я не нашел никакого способа сделать это, хотя.
Есть ли способ?