2013-10-15 27 views
8

私は何らかの例外をスローするメソッドを持っているとしましょう。例外をスローするコードは、外部サービスにアクセスする第三者のライブラリにあります。私は、外部サービスとの仕事を多くするいくつかのクラスを持っており、潜在的な問題に対処するためには、例外処理がたくさんあります。私が打つ問題は、例外がたくさんあるかもしれないということですが、もしあれば、いくつかのアクションの1つを実行する必要があります。例外のタイプは関連性がないかもしれませんし、異なるメソッドが同じタイプの例外を投げるかもしれませんが、投げるメソッドに応じて異なるアクションを取る必要があります。例外処理にアノテーションを使用していますか?

私が探しているのは、try/catchに取って代わることができ、そのメソッドに例外があるときに実行される動作を指示するアノテーションです。私はSpring ApsectJがこの種のことを行うことができることを知っていますが、私は現在、新しい依存関係を簡単に追加することも、既存のものを調整するためにpomを変更することもできません。このように、私はこれがカスタムアノテーションで達成できることを期待しています。例:

@Catcher(action=SomeEnum.SOME_ACTION) 
public void doSomething(ServiceObj obj) throws SomeException { 
    ExternalService.makeThingsHappen(obj); 
} 

もちろん、別のクラスが例外を処理すると仮定します。さらに難しいのは、渡されたServiceObjが必要であるということです。 makeThingsHappen()が失敗した場合、追加のアクションを実行するためにobjが必要な場合があります。アクション変数は、ハンドラクラスにobjと何をするかを伝えます。

これは重大な厄介なことなしに行うことができますか、存在しない可能性のあるものが欲しいですか?

+0

注釈は単独で動作を追加しません。それらはメタデータです。その動作を検出するとその動作を追加できるパーサを提供する必要があります。 –

+0

私はそれをマイナーなmuckeryと呼ぶだろう。 AOPやいくつかのバイトコード操作で簡単に処理できます。 –

答えて

17

これは低レベルのプロセスである必要があります。現在のレベルでは同じことをすることはできませんが、コードが必要でシステムが複雑になることがあります。 しかし私の提案はこのようなものです(私はそれが正しいことを望みます)、まず例外を処理したい人のためのインターフェースを定義します。

interface ExceptionHandler{ 
    void handleException(Throwable t); 
} 

ユーザー(API)がそのメソッドをマークする注釈を指定すると、例外がスローされることがあります。

次に、このような例外をスローする可能性があるメソッドを呼び出すためのインターフェイスが必要です。

interface Caller{ 
    void callMethod()throws Throwable; 
} 

、あなたが世話をし、実行の流れを管理し、可能な例外ハンドラを呼び出す

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

を、最終的には、いくつかの例を持っていることができます、それは私のために非常によく働く男を必要とし、かっこいいね。 例外ハンドラ。

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

とメソッド呼び出し側。

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

ご覧のように、ユーザーがcallmethod()方法でメソッドを呼び出す必要があり、あなたもCallerインタフェースを省略し、そしてそれは余分の束を必要とすることをクラスで複数のメソッドを宣言するために、アノテーションを使用しますコード。 私はいくつかの手を差し伸べることができれば幸いです。

2

ありがとうございました。私はSpring AOPを調べましたが、最終的にはそれに反対しました。try/catchブロックを使用して巻き上げましたが、各クラスに注入されたハンドラを作成し、例外クラスで例外をラップした後、ハンドラに渡します。それは専用のハンドラがあるという点でuser2511414の提案と少し似ていますが、注釈をあきらめました。私はtry/catchブロックの数が多いですが、少なくとも私は処理ロジックの大部分を残しています。

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

} 

その後MyExceptionを取る具象クラスでIExceptionHandlerを実装し、追加を読み出す:他の人々が少し難読化されており、これを見つけていますが、それでもポイントを得ることができた場合に私の解決策の迅速なランダウンデータに基づいてアクションを実行します。そして、このような例外をスローする可能性があり、各ブロックは、そのようにキャッチすることができます。

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

は今核心ザラザラのほとんどは、ハンドラ内でカプセル化され、のtry/catchブロックは最小限です。ハンドラは元の例外のスタックトレースを記録し、それに基づいて他の処理を行い、列挙型に基づいて独自のアクションを実行できます。たぶん完璧な解決策ではないかもしれませんが、ここで十分に機能します。