2014-04-13 6 views
7

Ich bin in ein bisschen Binden ... will meinen Kuchen und es auch essen.Jersey ... wie alle Ausnahmen zu protokollieren, aber immer noch ExceptionMappers aufrufen

Ich möchte alle Ausnahmen, die meine Anwendung wirft. Wenn also jemand eine falsche URL antrifft, möchte ich den Stack-Trace auf SLF4J protokollieren.

So sind Sie wahrscheinlich denken: ‚Hey, das ist einfach, nur eine ExceptionMapper implementieren und die Ausnahme log„Also tat ich.

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; 
    } 
} 

Wenn Sie dies tun, anstelle von 404-Fehler, wenn jemand Typen ein Falsche URL in, sie bekommen einen Fehler von 500. Man würde vermuten, dass das Zurückgeben von null die Ausnahme in den Kettenhandlern weitergibt, aber Jersey tut das nicht. Es liefert tatsächlich sehr wenig Informationen, warum es einen Handler über einen anderen wählen würde ...

Hat jemand dieses Problem gelöst und wie haben Sie es gelöst?

+0

I CDI Interceptor –

+0

Also, was verwenden würde, ist Ihr Problem: es ist der 404-Fehler Oder ist es, wie die Ausnahme Mapper ausgewählt werden? Oder etwas anderes? –

+0

Nein, das Problem ist, dass die "Lager" Abfangjäger, die mit Jersey versehen sind, nicht cal sind geführt, wenn Sie den obigen Code verwenden. 404 Fehler werden 500 Fehler. –

Antwort

6

den richtigen HTTP-Statuscode zurückzukehren, so etwas wie dies Ihre Ausnahme-Mapper aussehen könnte:

@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();    
    } 
} 
es klingt wie Sie

auch interessiert sind kaskadierende Ausnahme Mapper, sondern nach dem spec dies nicht möglich ist:

JAX-RS 2.0 Spec, Kapitel 4.4

„Exception-Mapping-Provider Karte eine karierte oder Runtime-Ausnahme auf eine Instanz Antwort. Eine Ausnahme Mapping-Provider implementiert die ExceptionMapper-Schnittstelle und kann mit @Provider für automatische Erkennung kommentiert werden. Wenn Sie einen Ausnahmezuordnungsanbieter zum Zuordnen einer Ausnahme auswählen, MUSS eine Implementierung den Anbieter verwenden, dessen generischer Typ die nächste Oberklasse der Ausnahme ist.

Wenn eine Ressourcenklasse oder eine Provider-Methode eine Ausnahme auslöst, für die ein Ausnahme-Provider zugeordnet ist, wird der passende Provider verwendet, um eine Response-Instanz zu erhalten. Die resultierende Antwort wird verarbeitet, als ob eine Webressourcenmethode die Antwort zurückgegeben hätte, siehe Abschnitt 3.3.3. Insbesondere wird ein abgebildet Antwort verarbeitet werden müssen, die ContainerResponse Filterkette in Kapitel definiert unter Verwendung 6.

eine potentiell unendliche Schleife zu vermeiden, eine einzige Ausnahme Mapper muss während der Verarbeitung einer Anforderung und der entsprechenden Reaktion verwendet werden. JAX-RS-Implementierungen dürfen NICHT versuchen, Exceptions zuzuordnen, die während der Verarbeitung einer zuvor von einer Exception gemappten Antwort ausgegeben werden. Stattdessen muss diese Ausnahme verarbeitet werden, wie in den Schritten 3 und 4 in Abschnitt 3.3.4 beschrieben.“

19

Sie ein RequestEventListener verwenden kann für ein Ausnahmeereignis zu hören und den throwable einzuloggen, ohne mit jeder vorhandenen Verarbeitung zu stören. Hinweis . zunächst, dass dies bedeutet eine ApplicationEventListener Registrierung, die dann eine Instanz von RequestEventListener kehrt

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

Ich denke, das ist die bessere Antwort, da OP nicht versucht, die Ausnahme einem bestimmten HTTP-Fehler zuzuordnen, sondern nur, um sie zu protokollieren. – uldall

+0

"Ich möchte alle Ausnahmen protokollieren, die von meiner Anwendung ausgelöst werden." Dies beantwortet tatsächlich die Frage. –

Verwandte Themen