より細かいポイントカットを行うためのポイントカット一覧


はじめに

時代が来るかも?アスペクト指向プログラミング, AspectJ言語とは何かをまとめていて、ポイントカットについて記述していたのだが、思いのほかポイントカットが多かった
長くて返って理解しづらくなったり、AspectJで実装されたポイントカットなどもあるみたいなのでわけることにした
独断と偏見でわけたのでご了承ください

まとめられなかったポイントカット

静的イニシャライザ関連のポイントカット

静的イニシャライザに関連するポイントカットにはstaticinitializationが用意されている
引数にタイプパターンを取り、クラスのstaticフィールドを初期化する静的イニシャライザが呼ばれて実行される「とき」を表す

Sample.java
// クラス名を直接書くか、ワイルドカードを使って書く
staticinitialization(Session+)

静的イニシャライザとは?

静的イニシャライザ(static initializer)、クラス・イニシャライザともいう
staticフィールドの値を初期化するために、各クラスごとに宣言される特別なメソッド

staticInitializer.java
static {
  // staticフィールドの値を初期化するコード
}

ジョインポイントの発生場所に関連するポイントカット

ポイントカットは演算子を使って組み合わせることができる
だが、注意が必要で上記の図のようにexecutionをcallが包んでいるように見えるのでcall && exectuionや
下のコードのように包んでいるように見えても、実際は違う

Sample.java
class Sample {
  Sample() {
    Main.init()
  }
}

class Main {
  static void init() {
    hoge();
  }
  static int length() {
    return hoge
  }
}

下の図のようにexecutionは水色の部分(ジョインポイントの外の部分)を指定していて、callは緑色の部分をしている状態なので
&& の条件がTrueになることはない

だが、このような条件を作りたい場合どうすればよいか
その解決策に特定の種類のジョインポイントを選択するもののほかに、プログラム中の場所を条件にジョインポイントを選択するプリミティブ・ポイントカットも提供している

within(タイプパターン)
タイプパターンに合致するクラスやインタフェースの宣言の中で発生するジョインポイントをすべて選択する
ジョインポイントの種類は問わない

withincode(メソッドパターン)またはwithincode(コンストラクタパターン)
引数のパターンに合致するメソッドやコンストラクタの本体の中で発生するジョインポイントをすべて選択する
ジョインポイントの種類は問わない

上記を使うことにより、特定のクラスやメソッド内という指定の仕方ができるようになる

業務フロー関連のポイントカット

業務フローに関連するポイントカットにはcflowcflowbelowの2つがある
引数にポイントカットを取り、「とき」を表す

Sample.java
cflow(call(void Main.init()))

cflow
引数のポイントカットが選択するジョインポイントPの開始から終了までの間に発生するすべてのジョインポイントを選択する
cflowは、引数のポイントカットによって選択されたジョインポイントPを選択する

cflowbelow
cflowとほぼ同じだが、cflowと異なり、引数のポイントカットによって選択されたジョインポイントPは選択しない

withincodeとcflowの違い

withincode

withincode.java
call(void Main.hogeB()) && withincode(void Main.init())

withincodeは引数のパターンに合致するメソッドの本体の中で発生するジョインポイントなので
この場合はmain.hogeAというメソッドが呼ばれるジョインポイントだけ
よってcall(void Main.hogeB())と一致するものが存在しない

cflow

cflow.java
call(void Main.hogeB()) && cflow(call(void Main.init()))

cflowは引数のポイントカットが選択するジョインポイントPの開始から終了までの間に発生するすべてのジョインポイントを選択するので
この場合はmain.hogeAとmain.hogeBというメソッドが呼ばれるジョインポイント
よってcall(void Main.hogeB())と一致するものが存在する

アドバイス関連のポイントカット

callポイントカットは、メソッドパターンで指定されたメソッドが呼び出される「とき」をジョインポイントとして選択する
このジョインポイントはメソッドだけではなく、アスペクトの定義の中にあらわれるメソッド呼び出しも対象となる
これはcall以外のポイントカットにも言えることである

無限の再起呼び出し問題

Hello.java
impoort java.io.*;
aspect Tracer {
  pointcut tracedMethods(): call(* PrintStream.println(..));

  before(): tracedMethods() {
    System.out.println("** method call");
  }
}

public class Hello {
  public static void say() {
    System.out.println("Hello");
  }
  public static void main(String[] args) {
    say();
  }
}

上記のようなプログラムを書くと無限ループになってしまう

この問題を避けるためにアドバイス関連のポイントカットにadviceexecutionがある
引数を取らず、任意のアドバイスの本体が実行されている「とき」を表す

Sample.java
!cflow(adviceexecution())
// アドバイスの本体を実行している間以外のすべてのジョインポイントを選択する

文脈情報を取り出すポイントカット

プログラムの実行文脈(context)の情報に関連するポイントカットにはthistargetargsの3つがある

this
ポイントカットの引数に一致する型(サブクラスやサブインタフェースも含む)のインスタンスが実行している、メソッドやコンストラクタの本体の中で発生したジョインポイントをすべて選択する
ジョインポイントの種類は問わない

target
ポイントカットの引数に一致する型(サブクラスやサブインタフェースも含む)のインスタンスを対象とするメソッド呼び出しやフィールド・アクセスを、ジョインポイントとしてすべて選択する
ジョインポイントの種類は問わない

args
ポイントカットの引数に一致する型の引数をとるメソッドやコンストラクタ呼び出しなどを、ジョインポイントとして選択する

thisポイントカットの使い方

this変数が指すオブジェクトのクラスとポイントカットの引数と一致するときジョインポイントを選択する

Sample.java
call(* *(..)) && this(Session)
// 上記はSessionクラス、またはそのサブクラスのメソッドの中から任意のメソッドの呼び出しをジョインポイントとして選択する

targetポイントカットの使い方

メソッド呼び出しやフィールド・アクセスの対象となっているオブジェクトのクラスの型とポイントカットの引数と一致するときジョインポイントを選択する

Sample.java
class Session {}
class BookSession extends Session{} 
Sample.java
call(* Session.*(..)) && target(BookSession)
// 上記はSessionクラスで宣言されているメソッドを呼び出しているときのうち、BookSessionオブジェクトに対して呼び出しているときだけをジョインポイントとして選択する

Session s = new BookSession(301);
s.doIt();

argsポイントカットの使い方

Sample.java
call(* *(..)) && args(BookSession, ..)
// 第一引数がBookSessionクラスのインスタンスであるようなメソッド呼び出しをジョインポイントとして選択する

argsポイントカットも、型を調べるとき、引数のオブジェクトの実際の型を使うことに注意

Boolean式を使ったポイントカット

名前付きポイントカット

参考