W jaki sposób powinienem rejestrować niezłapane wyjątki w mojej usłudze RESTful JAX-RS?
Mam serwis internetowy RESTful działający pod Glassfish 3.1.2 z wykorzystaniem Jersey i Jacksona:
@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;
}
}
Dla oczekiwanych wyjątków rzucam odpowiednieWebApplicationException
i jestem zadowolony ze statusu HTTP 500, który jest zwracany, jeśli wystąpi nieoczekiwany wyjątek.
Chciałbym teraz dodać rejestrację dla tych nieoczekiwanych wyjątków, ale mimo wyszukiwania nie mogę dowiedzieć się, jak japowinien chodzić o tym.
Bezowocna próbaPróbowałem użyć aThread.UncaughtExceptionHandler
i może potwierdzić, że jest on stosowany wewnątrz treści metody, ale jejuncaughtException
Metoda nigdy nie jest wywoływana, ponieważ coś innego obsługuje nieprzechwycone wyjątki, zanim dotrą do mojego handlera.
Inną opcją, którą widziałem, niektórzy ludzie używająExceptionMapper
, która łapie wszystkie wyjątki, a następnie odfiltrowuje 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();
}
}
}
Chociaż takie podejście może działać, wydaje mi się, że niewłaściwe użycie tego, do czego mają być używane wyjątki ExceptionMappers, to znaczy odwzorowanie pewnych wyjątków na pewne odpowiedzi.
Inne pomysły: # 2Większość przykładowego kodu JAX-RS zwracaResponse
obiekt bezpośrednio. Zgodnie z tym podejściem mogę zmienić mój kod na taki jak:
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();
}
}
Jednak nie podoba mi się pójście tą trasą, ponieważ mój rzeczywisty projekt nie jest tak prosty jak ten przykład i musiałbym zaimplementować ten sam wzorzec w kółko, nie wspominając już o konieczności ręcznego budowania odpowiedzi.
Co powinienem zrobić?Czy istnieją lepsze metody dodawania rejestrowania dla nieprzechwyconych wyjątków? Czy istnieje „właściwy” sposób wdrożenia tego?