У меня есть веб-сервис RESTful, работающий под Glassfish 3.1.2, используя Джерси и Джексона:
@Stateless
@LocalBean
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Path("users")
public class UserRestService {
private static final Logger log = ...;
@GET
@Path("{userId:[0-9]+}")
public User getUser(@PathParam("userId") Long userId) {
User user;
user = loadUserByIdAndThrowApplicableWebApplicationExceptionIfNotFound(userId);
return user;
}
}
Для ожидаемых исключений я бросаю соответствующий WebApplicationException
, и я доволен статусом HTTP 500, который возвращается, если неожиданно исключение.
Теперь я хотел бы добавить журнал для этих неожиданных исключений, но, несмотря на поиск, не могу узнать, как я должен это делать.
Бесполезная попытка
Я попытался использовать Thread.UncaughtExceptionHandler
и могу подтвердить, что он применяется внутри тела метода, но его метод uncaughtException
никогда не используется так как что-то еще обрабатывает неперехваченные исключения до того, как они достигнут моего обработчика.
Другие идеи: # 1
Другим вариантом, который я видел, является использование ExceptionMapper
, которое захватывает все исключения и затем отфильтровывает WebApplicationExceptions:
@Provider
public class ExampleExceptionMapper implements ExceptionMapper<Throwable> {
private static final Logger log = ...;
public Response toResponse(Throwable t) {
if (t instanceof WebApplicationException) {
return ((WebApplicationException)t).getResponse();
} else {
log.error("Uncaught exception thrown by REST service", t);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
// Add an entity, etc.
.build();
}
}
}
Несмотря на то, что этот подход может работать, мне кажется неправильным использование того, для чего должны использоваться ExceptionMappers, т.е. отображение определенных исключений для определенных ответов.
Другие идеи: # 2
В большинстве примеров кода JAX-RS напрямую возвращается объект Response
. Следуя этому подходу, я могу изменить свой код на что-то вроде:
public Response getUser(@PathParam("userId") Long userId) {
try {
User user;
user = loadUserByIdAndThrowApplicableWebApplicationExceptionIfNotFound(userId);
return Response.ok().entity(user).build();
} catch (Throwable t) {
return processException(t);
}
}
private Response processException(Throwable t) {
if (t instanceof WebApplicationException) {
return ((WebApplicationException)t).getResponse();
} else {
log.error("Uncaught exception thrown by REST service", t);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
// Add an entity, etc.
.build();
}
}
Тем не менее, я не люблю идти по этому маршруту, поскольку мой фактический проект не так прост, как этот пример, и мне пришлось бы повторять этот же шаблон снова и снова, не говоря уже о необходимости вручную создавать ответы.
Что мне делать?
Существуют ли более эффективные методы для добавления журнала для неперехваченных исключений? Есть ли "правильный" способ реализации этого?