2008.05.08

続・アノテーション

前回に引き続き、アノテーションについて書こうかと思います。
アノテーションについては、前回の記事を参照してください。

今回は、ありがちな例となってしまうのですが、
入力値のチェック処理での活用方法をご紹介します。

まず、チェック内容をあらわすアノテーションを宣言し、
そのアノテーションを、Bean の getter メソッドに対して宣言します。


(1)チェック内容をあらわすアノテーションを宣言します。
----------------------------------------------------------------------
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface RequiredCheck {
  String value(); //←(a)
}
----------------------------------------------------------------------

上記のコードでは、(a)のように、アノテーションにメソッドを宣言しています。
このように、アノテーションにはメソッドを宣言してメンバを保有することができます。
ただし、アノテーションの実体はインタフェースなので、
メソッドの具体的な挙動を記述することはできません。

メソッドは複数宣言することもできます。
上記のように単一のメソッドだけを宣言する場合は、
value()というメソッドを宣言するのが御作法のようです。
使用方法については、(2)の部分で行います。

(2)アノテーションを、TestBeanクラスのgetterメソッドに対して宣言します。
----------------------------------------------------------------------
import org.light.annotation.RequiredCheck;

public class TestBean {

  private String param = "";
  
  public void setParam(String param) {
    this.param = param;
  }

  @RequiredCheck("項目1")
  public String getParam() {
    return this.param;
  }

}
----------------------------------------------------------------------
上記のように、アノテーションに宣言したメソッドは、
アノテーションの型名に続いて ( ) でメンバの値を初期化する必要があります。

上記では、必須入力チェックを表す RequiredCheck アノテーションを
getParam()メソッドに対して宣言し、項目名を "項目1" で初期化しています。
※ここで宣言した項目名は、エラーメッセージを表示する際に使用します。

RequiredCheck アノテーションはメンバを保有しているため、
アノテーションを指定したときに ( ) 内にアノテーションの
メンバを初期化させなければなりません。

ちなみに、RequiredCheck アノテーションは、
宣言されているメソッドが1つで、且つ、value()というメソッドを宣言しているため、
@アノテーション型(値)という宣言で済みます。
これは、value()というメソッドが言語で予約されているためです。

通常は、@アノテーション型(メソッド名=値)と宣言する必要があります。
上記の場合だと、「@RequiredCheck(value="項目1")」となります。
複数メソッドが宣言されていた場合は、
@アノテーション型(メソッド名=値,メソッド名=値,...)と宣言します。

(3)TestBean クラスの入力チェックを行います。
----------------------------------------------------------------------
public static void main(String[] args) throws Exception {

  TestBean bean = new TestBean();
  bean.setParam("");

  Class clazz = bean.getClass();
  BeanInfo beanInfo = Introspector.getBeanInfo(clazz);

  // TestBean のプロパティメソッドの情報を全て取得する
  PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
  for (int i1 = 0; i1 < pds.length; i1++) {
    // getter メソッドに宣言されているアノテーション情報を取得する
    Method method = pds[i1].getReadMethod();
    Annotation[] annotations = method.getDeclaredAnnotations();
    for (int i2 = 0; i2 < annotations.length; i2++) {
      internalValidate(bean, annotations[i2], method);
    }
  }

}


private static void internalValidate(Object bean
                 , Annotation annotation
                 , Method method) throws Exception {

  // アノテーションが RequiredCheck の場合、必須入力チェックを行う。
  if ( annotation instanceof RequiredCheck) {
    String sValue = (String)method.invoke(bean, new Object[0]);
    if ( sValue == null || "".equals(sValue) ) {
      // エラーの場合、RequiredCheck アノテーションの
      // value()メソッドから項目名を取得してメッセージを生成する
      RequiredCheck req = (RequiredCheck)annotation;
      System.out.println(req.value() + "は、必須入力です。");
    }
  }

}
----------------------------------------------------------------------


(4)実行結果
----------------------------------------------------------------------
項目1は、必須入力です。
----------------------------------------------------------------------


以上のようにアノテーションを利用すれば、
どの項目に対して、どのような入力チェック処理を実行するかを、
自由に宣言することができます。
こうすることによって、入力チェックロジックを個別に実装せずに、
自動的にチェック処理を実行することが可能になります。

コメントを投稿

(いままで、ここでコメントしたことがないときは、コメントを表示する前にこのブログのオーナーの承認が必要になることがあります。承認されるまではコメントは表示されません。そのときはしばらく待ってください。)

photo
ykato