2013-10-15 12 views
8

Angenommen, ich habe eine Methode, die eine Ausnahme auslöst. Der Exception-throwing-Code liegt in einer Drittanbieterbibliothek, die auf einen externen Dienst zugreift. Ich habe ein paar Klassen, die eine Menge Arbeit mit externen Diensten machen, und es gibt eine Menge von Exception-Behandlung, um mit potenziellen Problemen umzugehen. Das Problem, das ich treffe, ist, dass ich viele Ausnahmen haben kann, aber ich muss vielleicht nur eine der wenigen Aktionen ausführen, wenn es eine gibt, und es gibt eine Tonne von Versuchen/Catch-Blöcken, die gespickt sind. Der Typ der Ausnahme ist möglicherweise nicht einmal relevant, oder verschiedene Methoden können den gleichen Typ von Ausnahme auslösen, aber abhängig von der Methode, die sie auslöst, müssen verschiedene Aktionen ausgeführt werden.Verwenden von Anmerkungen für die Ausnahmebehandlung?

Was ich suche ist eine Annotation, die Versuch/Fang ersetzen kann und diktieren Sie einfach das Verhalten, wenn eine Ausnahme in dieser Methode ist. Ich weiß, dass Spring ApsectJ so etwas tun kann, aber ich bin derzeit nicht in der Lage, einfach neue Abhängigkeiten hinzuzufügen oder den Pom zu modifizieren, um bestehende anzupassen. Daher hoffe ich, dass dies mit einer benutzerdefinierten Anmerkung erreicht werden kann. Zum Beispiel:

Ich würde annehmen, dass eine separate Klasse natürlich Ausnahmen behandeln würde. Eine zusätzliche Schwierigkeit ist, dass ich das ServiceObj, das auch übergeben wird, benötigen würde. Wenn makeThingsHappen() fehlschlägt, muss obj möglicherweise weitere Aktionen ausführen. Die Aktionsvariable teilt der Handler-Klasse mit, was mit obj geschehen soll.

Kann dies ohne schwere Missgunst geschehen, oder hoffe ich auf etwas, das vielleicht nicht existiert?

+0

Anmerkungen verursachen kein eigenständiges Verhalten. Sie sind Metadaten. Sie müssen für sie einen Parser bereitstellen, der dieses Verhalten hinzufügen kann, wenn er sie findet. –

+0

Ich würde es als minderwertigen Schmutz bezeichnen; Es kann trivial mit AOP oder einige Byte-Code-Manipulation behandelt werden. –

Antwort

17

Dies sollte ein Low-Level-Prozess sein, und es bedeutet nicht, dass wir nicht das gleiche mit dem aktuellen Niveau haben können, aber es braucht möglicherweise eine Menge Code und würde das System ein wenig komplex. Allerdings würde mein Vorschlag so sein (ich hoffe, ich habe es richtig), definieren Sie zuerst eine Schnittstelle für wer Ausnahmen verarbeiten möchte, so etwas.

interface ExceptionHandler{ 
    void handleException(Throwable t); 
} 

dann eine Annotation für Benutzer (API) zur Verfügung stellen, um seine Methoden zu markieren, kann eine Ausnahme auslösen. Als nächstes brauchen wir eine Schnittstelle, um zu starten, um die Methode aufzurufen, die eine Exception auslösen kann, so etwas wie diese.

interface Caller{ 
    void callMethod()throws Throwable; 
} 

dann brauchen Sie einen Mann, der die Pflege und den Fluss der Ausführung verwalten und den möglichen Exception-Handler

class MethodCaller{ 
    /* 
    * @param isntance: instance which implemented the Caller interface 
    */ 
    public static void callMethod(Caller instance) 
     throws Exception { 
    Method m = instance.getClass().getMethod("callMethod"); 
    Annotation as[] = m.getAnnotations(); 
    Catch[] li = null; 
    for (Annotation a : as) { 
     if (a.annotationType().equals(CatchGroup.class)) { 
     li = ((CatchGroup) a).catchers(); 
     } 
     // for(Catch cx:li){cx.targetException().getName();} 
    } 
    try { 
     instance.callMethod(); 
    } catch (Throwable e) { 
     Class<?> ec = e.getClass(); 
     if (li == null) { 
     return; 
     } 
     for (Catch cx : li) { 
     if (cx.targetException().equals(ec)) { 
      ExceptionHandler h = cx.targetCatchHandler().newInstance(); 
      h.handleException(e); 
      break; 
     } 
     } 
    } 
    } 
} 

und schließlich nennt, lasse einiges Beispiel hat, ist es für mich sehr gut funktioniert, es ist cool. der Ausnahmebehandler.

public class Bar implements ExceptionHandler{//the class who handles the exception 
    @Override 
    public void handleException(Throwable t) { 
    System.out.println("Ta Ta"); 
    System.out.println(t.getMessage()); 
    } 
} 

und die Methode Anrufer.

class Foo implements Caller{//the class who calls the method 
    @Override 
    @CatchGroup(catchers={ 
     @Catch(targetCatchHandler=Bar.class,targetException=ArithmeticException.class), 
     @Catch(targetCatchHandler=Bar.class,targetException=NullPointerException.class)}) 
    public void callMethod()throws Throwable { 
    int a=0,b=10; 
    System.out.println(b/a); 
    } 
    public static void main(String[] args) throws Exception { 
    Foo foo=new Foo(); 
    MethodCaller.callMethod(foo); 
    } 
} 

wie Sie sehen, der Benutzer hat die callmethod() Verfahren die Methoden aufrufen, würden Sie auch die Caller Schnittstelle weglassen, und verwenden Sie Anmerkung mehr als eine Methode in einer Klasse zu erklären, dass es eine Reihe von zusätzlichen braucht Codez. Ich hoffe, ich könnte etwas geben.

2

Danke für die Hilfe, alle. Ich habe mir Spring AOP angesehen, habe mich aber letztendlich dagegen entschieden.Ich habe versucht, try/catch-Blöcke zu verwenden, aber einen Handler zu erstellen, der in jede Klasse injiziert wird und alle ausgelösten Ausnahmen in meine eigene Ausnahmeklasse einfügt und diese dann an den Handler in einer einzigen Zeile weitergibt. Es ist ein bisschen ähnlich dem Vorschlag von user2511414, dass es einen dedizierten Handler gibt, aber ich habe die Annotationen aufgegeben. Ich habe eine gute Anzahl von Try/Catch-Blöcken, aber zumindest habe ich den Großteil der Handling-Logik ausgehalten. Ein kurzer Überblick über meine Lösung bei anderen Leuten das finden, was ein wenig verschleiert ist, aber man kann immer noch den Punkt:

public enum DoThisEnum { 
    DO_THIS, 
    DO_THAT, 
    DO_OTHER_THING; 
} 

public class MyException extends Exception { 

    private DoThisEnum doThis; 
    private MyObject dataObj; 

    //Constructor, overloaded to run super(originalException) or super() 
    //as well as taking doThis and dataObj as parameters 
    //Getters, setters, etc 
} 

public interface IExceptionHandler { 

    void handleException(MyException exception); 

} 

Dann mit einer konkreten Klasse der IExceptionHandler implementieren, die MyException nimmt, liest die zusätzlichen Daten und führt darauf basierende Aktionen aus. Dann wird jeder Block, der eine solche Ausnahme werfen könnte kann wie so gefangen werden:

... 
try { 
    doSomething(Object data); 
} catch (SomeException e) { 
    handler.handleException(new MyException(e, DoThisEnum.DO_THAT, data)); 
    //Anything else to do, maybe return or return null, rethrow, etc. 
} 

Jetzt sind die meisten der winzigsten wird in dem Handler gekapselt und die try/catch-Blöcke sind minimal. Der Handler kann den Stack-Trace der ursprünglichen Exception protokollieren, möglicherweise andere darauf basierende Aktionen ausführen und dann auf der Basis der Enumeration eigene Aktionen ausführen. Vielleicht ist es nicht die perfekte Lösung, aber es funktioniert hier gut genug.