2013-11-14 5 views
9

In meinem Grails Dienst gefangen Ich habe Code wie folgt aus:Ausnahme vom Dienst Geworfen Nicht-Controller

def createCharge(chargeParams) { 
    try { 
    def charge = Charge.create(chargeParams) 
    } catch (CardException e) { 
    throw e 
    } 
} 

Von meinem Controller ich folgendes:

try { 
    service.createCharge(chargeParams) 
} catch(CardException e) { 

} 

jedoch mein Controller ist nicht das erneute Werfen der CardException abfangen. Wenn ich CardException wickeln in einem Runtime über:

throw new RuntimeException(e) 

und/oder die Signatur aus dem Fang zu entfernen, um nur zu fangen (e), ohne es zu tippen, es funktioniert, aber ich verlieren einige Informationen aus der Ausnahme, wie die Nachricht .

Als Hinweis ist CardException eine Ausnahme, kein Runtime. Ich bin mir nicht sicher, ob das wichtig ist.

Antwort

11

Im Gegensatz zu Java müssen Sie die (aktivierten) Ausnahmen, die von einer Groovy-Methode ausgelöst werden, nicht deklarieren, da alle nicht deklarierten Ausnahmen in eine UndeclaredThrowableException eingeschlossen sind. So folgt aus:

def createCharge(chargeParams) { 
    try { 
    def charge = Charge.create(chargeParams) 
    } catch (CardException e) { 
    throw e 
    } 
} 

ist das Gleiche wie:

def createCharge(chargeParams) throws UndeclaredThrowableException { 
    try { 
    def charge = Charge.create(chargeParams) 
    } catch (CardException e) { 
    throw new UndeclaredThrowableException(e) 
    } 
} 

die Ausnahme von der oben geworfen, wäre natürlich nicht gefangen werden:

try { 
    service.createCharge(chargeParams) 
} catch(CardException e) { 

} 

Aber es wird gefangen werden von:

try { 
    service.createCharge(chargeParams) 
} catch(e) { 

} 

Da diese nur eine Abkürzung für:

try { 
    service.createCharge(chargeParams) 
} catch(Exception e) { 

} 
+0

Nun, ich brauche überprüfte Ausnahmen in meinem Fall, weil es mehrere gibt, die ich von der Stripe API behandeln muss. Ich habe einen anderen Weg eingeschlagen, da ich auch immer eine RuntimeException auslösen muss, damit meine Transaktionen korrekt zurückgesetzt werden. Ich markiere deine Antwort als richtig, weil es die richtige Antwort auf meine Frage ist. Vielen Dank. – Gregg

+2

Gern geschehen. Übrigens, Sie können Transaktionen für alle Ausnahmen rückgängig machen (aktiviert und deaktiviert), indem Sie den Grails-Diensten die folgende Anmerkung hinzufügen: @Transactional (rollbackFor = Throwable) –

+0

Danke für den Tipp! Wusste ich nicht. – Gregg

8

Im Gegensatz zu Java, Sie müssen nicht die (überprüft) Ausnahmen erklären, die von einer starken Methode geworfen werden, da alle nicht angemeldete geprüfte Ausnahmen in einem UndeclaredThrowableException gewickelt werden.

Sie scheinen zu implizieren, dass Groovy Wraps Ausnahmen von einem UndeclaredThrowableException geprüft, dann ist dies nicht der Fall. Wenn ein Grails-Dienst eine ungeprüfte Exception wirft die Exception schließlich von einer UndeclaredThrowableException wrappped aber dies ist ein java.lang.reflection Mechanismus und tritt nur dann auf, wenn eine Proxy-Klasse beteiligt ist.

Dies geschieht, der Fall zu sein, weil ein Grails Dienst beteiligt ist. Ich bin mir nicht sicher, wie viele Proxy-Klassen genau beteiligt sind, durch mindestens eine ist: eine Klasse, die die Transaktion tut Handling (von Spring).

Die Klasse wird jede Methode im Service mit einer Transaktion umbrechen und die Transaktion rückgängig machen, wenn eine RuntimeException auftritt. Die Verarbeitung von Spring-Transaktionen wird standardmäßig nicht rückgängig gemacht, wenn eine Ausnahme aktiviert ist.

Java

Dies macht Sinn, in plain old Java, da der Entwickler die Ausnahme in dem Anwendungscode sehen und wird gewarnt, etwas dagegen zu tun. Wenn der Entwickler schlau ist, wird er im Rahmen einer Transaktion mit Ausnahmen umgehen.Wenn er die Transaktion nicht zurücksetzt, sagt er im Wesentlichen: "In dieser Situation ist die Datenintegrität, die durch die Transaktion bereitgestellt wird, für mich nicht wichtig. Ich werde auf andere Weise“

Groovy

diese Fehler beheben Dies macht keinen Sinn in einer Groovy Welt machen, weil die Groovy-Compiler nicht den Umgang mit Ausnahmen nicht erzwingen. Es behandelt Ausnahmen genauso wie RuntimeExceptions.

Es gibt jedoch eine Einschränkung: Der Reflektionsmechanismus sieht eine Exception, die vom Proxy ausgelöst wird und nicht in der Methodensignatur des ursprünglichen Service enthalten ist. Dies ist möglich, weil:

  1. Groovy erzwingt nicht die Ausnahmen Umgang
  2. Ein Proxy-Methode immer alle Throwable (check InvocationHandler JavaDoc) werfen

Da die verwendete Reflexionsmechanismus von Java ist, Es muss den Java-Regeln entsprechen. Es muss also die Exception in eine RuntimeException umbrechen, in diesem Fall eine UndeclaredThrowableException.

Grails

Jetzt wird es wirklich schwierig, denn wenn Sie Ihre Service-Methode von einem Controller-Aufruf und eine Ausnahme auftritt. Sie werden eine RuntimeException-Blase sehen (wegen eines versteckten Mechanismus), aber Ihre Transaktion wird nicht zurückgesetzt (wegen eines versteckten Mechanismus).

Dieses Verhalten ist sehr gefährlich wie der Entwickler wirklich zu erinnern, hat richtig mit allen möglichen Ausnahmen zu behandeln (das der Compiler mit nicht helfen) oder dem Entwickler muss sicherstellen, dass jeder Dienst ordnungsgemäß mit @Transactional angewiesen wird (rollbackFor = Throwable).

Dies ist ein Design-Problem, das die Entwickler von Grails meiner Meinung nach übersehen haben, als sie es zum ersten Mal entwarfen. Aber ich denke, das Standardverhalten ist so falsch und so gefährlich, das sollte wirklich geändert werden.

2

Ich denke, die einfache Lösung für das Problem besteht darin, eine throws CardException-Anweisung zur Service-Methode hinzuzufügen, damit die Ausnahme nicht mehr in UndeclaredThrowableException eingewickelt wird und der Controller den richtigen Ausnahme-Typ abfängt.

0

Fangen Sie einfach die UndeclaredThrowableException, erhalten Sie die Nachricht von ihm, und dann erneut werfen, wenn nötig.

Das obige Codefragment fängt nur die Ausnahme ein, die Sie explizit in den Code geworfen haben (z. B. CardException). Zum Beispiel wird eine NullPointerException nicht abgefangen und platzt auf.