2016-04-19 12 views
1

と仮定私は、次の再帰関数は、引数の初期値は10を言うのであれば、私は側面に例外をスローしたい検証パラメータ

public class MyClass{ 
    public int foo(int arg){ 
     ... 
    } 
} 

(それはそれのために大丈夫です持っていますその後になる)。私はAspectJを初めて使っていますが、動作していないような次のものを考え出しました。

public aspect CheckBounds{ 
    pointcut initialCall(int x): 
     call(int MyClass.foo(int)) 
     && !cflow(call(int MyClass.foo(int))) 
     && args(x); 

    before(int x) : initialCall(x){ 
     if(x == 10){ 
      throw new IllegalArgumentException("x must not be 10"); 
     } 
    } 
} 

これを達成するための提案や推奨方法はありますか?

答えて

1

まず、独自のソリューションが動作しないことができます:withincode()がポイントカットのパラメータを取りませんので!withincode(call(int MyClass.foo(int)))はコンパイルされません。 、署名のみ。だからそれは本当にあるべきです:!withincode(int MyClass.foo(int))

第2に、自分の答えのソリューションは間接的な再帰ではなく、直接的な再帰のためだけに働くので、あなたが本当に望むのはあなたの初期のソリューションと似ています。あなたが見ることができるように、

package de.scrum_master.app; 

public class Application { 
    public static void main(String[] args) { 
     Application application = new Application(); 
     System.out.println("Directly recursive factorials:"); 
     for (int i = 0; i < 12; i++) 
      System.out.printf("%2d! = %10d%n", i, application.factorial(i)); 
     System.out.println("\nIndirectly recursive factorials:"); 
     for (int i = 0; i < 12; i++) 
      System.out.printf("%2d! = %10d%n", i, application.factorial_indirect(i)); 
    } 

    public int factorial(int i) { 
     return i > 1 ? i * factorial(i - 1) : 1; 
    } 

    public int factorial_indirect(int i) { 
     return helper(i); 
    } 

    public int helper(int i) { 
     return i > 1 ? i * factorial_indirect(i - 1) : 1; 
    } 
} 

それが今度は、元を呼び出すhelper(int)を呼び出すためfactorial_indirect(int)が間接再帰を経由してそうに対しfactorial(int)は、直接再帰による階乗を計算します。

ドライバアプリケーション:ここでは一例ですメソッドを再度実行します。私は両方の状況に対応し、最初の呼び出しをブロックし、直接的または間接的に再帰的な呼び出しをブロックしないという側面を提示します。

アスペクト比:あなたの質問から元のポイントカットはほぼ正しかった

、それだけでcflowbelow()の代わりcflow()を使用している必要があります。

私は実際に例外を投げているわけではなく、プログラムの流れを中断しないようにデモ目的でログするだけです。

package de.scrum_master.aspect; 

import de.scrum_master.app.Application; 

public aspect CheckBounds { 
    pointcut factorialCall() : 
     call(int Application.factorial*(int)); 

    pointcut initialFactorialCall(int i) : 
     factorialCall() && 
     !cflowbelow(factorialCall()) && 
     args(i); 

    pointcut initialFactorialCall2(int i) : 
     factorialCall() && 
     !withincode(int Application.factorial*(int)) && 
     args(i); 

    before(int i) : initialFactorialCall(i) { 
     if (i < 1 || i == 10) { 
      System.out.println(new IllegalArgumentException("x must be >=1 and != 10")); 
     } 
    } 
} 

コンソールログ:

Directly recursive factorials: 
java.lang.IllegalArgumentException: x must be >=1 and != 10 
0! =   1 
1! =   1 
2! =   2 
3! =   6 
4! =   24 
5! =  120 
6! =  720 
7! =  5040 
8! =  40320 
9! =  362880 
java.lang.IllegalArgumentException: x must be >=1 and != 10 
10! = 3628800 
11! = 39916800 

Indirectly recursive factorials: 
java.lang.IllegalArgumentException: x must be >=1 and != 10 
0! =   1 
1! =   1 
2! =   2 
3! =   6 
4! =   24 
5! =  120 
6! =  720 
7! =  5040 
8! =  40320 
9! =  362880 
java.lang.IllegalArgumentException: x must be >=1 and != 10 
10! = 3628800 
11! = 39916800 

あなたが直接および間接的な再帰例ともに0と10の初期値のための私のテスト条件ログのエラーを見ることができるように。今、私たちはbefore()アドバイスにinitialFactorialCall2(i)に切り替えた場合、間接的なケースのためにログに変わり:

Indirectly recursive factorials: 
java.lang.IllegalArgumentException: x must be >=1 and != 10 
0! =   1 
1! =   1 
2! =   2 
3! =   6 
4! =   24 
5! =  120 
6! =  720 
7! =  5040 
8! =  40320 
9! =  362880 
java.lang.IllegalArgumentException: x must be >=1 and != 10 
10! = 3628800 
java.lang.IllegalArgumentException: x must be >=1 and != 10 
11! = 39916800 

例外もfactorial_indirect(10)の内部呼び出しのために記録されます11!の間違った反応を注意してください。これは明らかに間違っているので、代わりにcflowbelow()ソリューションを利用したいと考えています。

+0

説明をありがとう!しかし、奇妙なことに、私はオリジナルの解法で構文エラーを起こさず、直接再帰のために働いていました。何か案は? –

+0

不可能です。コピー&ペーストを使用してIDEで修正したものをここで調整するのを忘れた可能性があります。私は私の答えに記載されている結果で両方のアプローチを試みました。ここからもう一度コピーして、自分で見てください。 :-) – kriegaex

+0

こんにちは、私は疑問に思っていました。あなたはどのようにしますか?入力を常に1にしたい場合は、最初の呼び出しでのみ、パラメータの値を1に変更しますか? –

0

間違ったポイントカットを使用していたことが判明しました。私の意図は、foo()の呼び出しがfoo(直接呼び出しのみ)内で行われていないことを保証することでした。 「withincode」から「CFLOW」を変更することでアドバイスが今期待通りに機能している:それは構文エラーが含まれているため

public aspect CheckBounds{ 
    pointcut initialCall(int x): 
     call(int MyClass.foo(int)) 
     && !withincode(int MyClass.foo(int)) 
     && args(x); 

    before(int x) : initialCall(x){ 
     if(x == 10){ 
      throw new IllegalArgumentException("x must not be 10"); 
     } 
    } 
} 
+0

構文エラーが含まれているため、このソリューションは動作しません。'withincode()'がポイントカットパラメータをとらないので、withincode(call(int MyClass.foo(int))) 'はコンパイルされません。ですから、実際には '!withincode(int MyClass.foo(int))'でなければなりません。さらに、この解決策は間接的な直接的な再帰ではなく、直接的にしか機能しません。イラストとより良い解決方法については、自分の答えを見てください。 – kriegaex

+0

あなたが正しいです、pointcutパラメータが無効な構文でした。 –

関連する問題