2014-04-13 15 views
7

Sono un po 'in difficoltà ... voglio la mia torta e anche a mangiarla.Jersey ... come registrare tutte le eccezioni, ma invocare ancora ExceptionMappers

Desidero registrare tutte le eccezioni generate dalla mia applicazione. Quindi, se qualcuno colpisce un URL errato, voglio registrare la traccia dello stack su SLF4J.

Quindi probabilmente stai pensando, 'hey questo è semplice, basta implementare un exceptionmapper e registrare l'eccezione "Così ho fatto:.

public class RestExceptionMapper implements ExceptionMapper<java.lang.Exception> { 
    private static final Logger log = LoggerFactory.getLogger(RestExceptionMapper.class); 

    /** 
    * {@inheritDoc} 
    */ 
    @Override 
    public Response toResponse(Exception exception) { 
     log.error("toResponse() caught exception", exception); 
     return null; 
    } 
} 

Se si esegue questa operazione, invece di 404 errori quando qualcuno digita un URL errato in, ottengono un errore 500. Si potrebbe supporre che restituire null propagherebbe l'eccezione ai gestori della catena, ma Jersey non lo fa, in realtà fornisce pochissime informazioni sul perché sceglierebbe un gestore su un altro ...

Qualcuno si è imbattuto in questo problema e come lo ha risolto?

+0

userei CDI intercettore –

+0

quindi, qual è il tuo problema: è la 404 errori O è come vengono scelti i mapper di eccezione? ? O qualcos'altro? –

+0

No, il problema è che gli intercettori "stock" forniti con Jersey non sono cal led se usi il codice sopra. 404 errori diventano 500 errori. –

risposta

6

Per riportare il codice di stato HTTP corretto, la vostra mapper eccezione potrebbe essere simile a questa:

@Provider 
public class RestExceptionMapper implements ExceptionMapper<Throwable> 
{ 
    private static final Logger log = LoggerFactory.getLogger(RestExceptionMapper.class); 

    @Override 
    public Response toResponse(Throwable exception) 
    { 
     log.error("toResponse() caught exception", exception); 

     return Response.status(getStatusCode(exception)) 
       .entity(getEntity(exception)) 
       .build(); 
    } 

    /* 
    * Get appropriate HTTP status code for an exception. 
    */ 
    private int getStatusCode(Throwable exception) 
    { 
     if (exception instanceof WebApplicationException) 
     { 
      return ((WebApplicationException)exception).getResponse().getStatus(); 
     } 

     return Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(); 
    } 

    /* 
    * Get response body for an exception. 
    */ 
    private Object getEntity(Throwable exception) 
    { 
     // return stack trace for debugging (probably don't want this in prod...) 
     StringWriter errorMsg = new StringWriter(); 
     exception.printStackTrace(new PrintWriter(errorMsg)); 
     return errorMsg.toString();    
    } 
} 

Inoltre suona come siete interessati a cascata mapper di eccezione, ma secondo le specifiche questo non è possibile:

JAX-RS 2.0 Spec, capitolo 4.4

"fornitori di mappatura delle eccezioni mappare un'eccezione controllata o di runtime a un'istanza di risposta. Un'eccezione del provider di mappe implementa l'interfaccia ExceptionMapper e può essere annotata con @Provider per il rilevamento automatico. Quando si sceglie un provider di mapping delle eccezioni per mappare un'eccezione, un'implementazione DEVE utilizzare il provider il cui tipo generico è la superclasse più vicina all'eccezione.

Quando un metodo di classe di risorsa o provider genera un'eccezione per la quale esiste un provider di associazioni di eccezioni , il provider di corrispondenza viene utilizzato per ottenere un'istanza di risposta. La risposta risultante viene elaborata come se un metodo di risorsa Web avesse restituito la risposta, vedere Sezione 3.3.3. In particolare, una mappata risposta deve essere lavorato con la catena di filtri ContainerResponse definito nel Capitolo 6.

Per evitare un loop potenzialmente infinito, un singolo mappatore eccezione deve essere impiegati nel trattamento di una richiesta e la risposta corrispondente. Le implementazioni JAX-RS NON DEVONO tentare di mappare le eccezioni generate durante l'elaborazione di una risposta precedentemente mappata da un'eccezione. Invece, questa eccezione deve essere trattati come descritto ai punti 3 e 4 nella sezione 3.3.4."

19

è possibile utilizzare un RequestEventListener per ascoltare un evento di eccezione e registrare il throwable, senza interferire con alcuna elaborazione esistente. Nota . che questo significa prima registrazione di un ApplicationEventListener che poi restituisce un'istanza di RequestEventListener

public class ExceptionLogger implements ApplicationEventListener, RequestEventListener { 

    private static final Logger log = LoggerFactory.getLogger(RequestExceptionLogger.class); 

    @Override 
    public void onEvent(final ApplicationEvent applicationEvent) { 
    } 

    @Override 
    public RequestEventListener onRequest(final RequestEvent requestEvent) { 
     return this; 
    } 

    @Override 
    public void onEvent(RequestEvent paramRequestEvent) { 
     if(paramRequestEvent.getType() == Type.ON_EXCEPTION) { 
      log.error("", paramRequestEvent.getException()); 
     } 
    } 
} 
+0

Penso che questa sia la risposta migliore poiché OP non sta tentando di mappare l'eccezione a un errore HTTP specifico ma solo di registrarlo. – uldall

+0

"Voglio registrare tutte le eccezioni generate dalla mia applicazione." Questo in realtà risponde alla domanda. –

Problemi correlati