Javaで記述されたコンポーネント間で、まとまった情報をやり取りしたい場合は、JavaBeansを使用すると便利です。JavaBeansのプロパティxxxに値をセットしたり取得したりするには、setXxx()やgetXxx()メソッドを呼ぶコードを記述します。しかし、XML形式の設定ファイル内に、JavaBeansにセットしたいプロパティ名と値の組が記述されていた場合等、アクセスしたいプロパティのプロパティ名を文字列として指定したい場合があります。このようなときは、java.lang.reflectパッケージによるリフレクションを用いて、プロパティ文字列に対応するsetter/getterメソッドを呼ぶコードを記述するのが一般的ですが、リフレクションを使用したコードは記述が大変で読みにくく、保守性が低くなるという問題があります。この問題はBeanUtilsを用いると解決します。
BeanUtilsは、Jakarta Commonsプロジェクトの産物であり、JavaBeansを容易に扱えるようにするためのユーティリティです。
BeanUtilsのダウンロードはhttp://jakarta.apache.org/commons/beanutils/から行えます。執筆時点の最新版はバージョン1.5です。また、実行にはJakarta Commons Logging(http://jakarta.apache.org/commons/logging/からダウンロード可能)のcommons-logging.jarも必要です。ダウンロードしたzipファイルを展開して出てきたcommons-beanutils.jar、およびcommons-logging.jar双方にクラスパスに通すことでjavaコードから使用可能になります。
BeanUtilsに含まれるorg.apache.commons.beanutils.PropertyUtilsBeanクラスを用いると、アクセスしたいプロパティを文字列として指定することができ、しかもリフレクションを用いた場合よりもコードの記述性や見通しが良くなります。さらに、PropertyUtilsBeanには以下のような機能もあります。
- あるJavaBeansのプロパティaに格納された値が別のJavaBeansになっている場合、ネストしたJavaBeansのプロパティbを「a.b」のように文字列として指定し、直接アクセスする
- プロパティcに格納された値が配列である場合、配列のn番目の要素を「c[2]」(n=2の場合)のように文字列として指定し、直接アクセスする
- プロパティdに格納された値がMapである場合、あるキーを持つ要素を「d(somekey)」(キーがsomekeyの場合)のように文字列として指定し、直接アクセスする
- 2つのJavaBeansのインスタンス同士で共通するプロパティ名の内容をコピーする
これらの機能をリフレクションを用いて実装するのはとても大変ですが、BeanUtilsのPropertyUtilsBeanでは簡単に使用することができます。
プロパティ名を文字列として指定し、プロパティにアクセスするにはPropertyUtilsBean#setProperty、PropertyUtilsBean#getPropertyを使用します。2つのJavaBeansのインスタンス同士で共通するプロパティ名の内容をコピーするにはPropertyUtilsBean#copyPropertiesを使用します。
SampleBeanとSampleBean2というJavaBeansのインスタンスに対して、BeanUtilsを用いてプロパティにアクセスする例をBeanUtilsSample.javaに示します。配列のインデックスやMapのキーを文字列で指定することで、プロパティに格納された配列やMapインスタンス内の1要素に簡単にアクセスできていることが分かります。
SampleBean.java
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
public class SampleBean implements Serializable {
public class InnerClass {
private String message;
public String getMessage() { return this.message; }
public void setMessage(String message) {
this.message = message;
}
}
private String foo;
private Integer[] intarray = new Integer[3];
private Map table = new HashMap();
private InnerClass inner = new InnerClass();
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return this.foo; }
public void setIntarray(Integer[] intarray) {
this.intarray = intarray;
}
public Integer[] getIntarray() { return this.intarray; }
public void setInner(InnerClass inner) { this.inner = inner; }
public InnerClass getInner() { return this.inner; }
public void setTable(Map table) { this.table = table; }
public Map getTable() { return this.table; }
} |
SampleBean2.java
import java.io.Serializable;
public class SampleBean2 implements Serializable {
private String foo;
public void setFoo(String foo) { this.foo = foo; }
public String getFoo() { return this.foo; }
} |
BeanUtilsSample.java
import java.lang.reflect.InvocationTargetException;
import org.apache.commons.beanutils.PropertyUtilsBean;
public class BeanUtilsSample {
public static void main(String[] args) {
try {
SampleBean bean = new SampleBean();
SampleBean2 bean2 = new SampleBean2();
PropertyUtilsBean util = new PropertyUtilsBean();
// fooプロパティにアクセス
util.setProperty(bean, "foo", "bar");
System.out.println((String)util.getProperty(bean, "foo"));
// innerプロパティに格納されたJavaBeansのmessage
// プロパティに直接アクセス
util.setProperty(bean, "inner.message", "foobar");
System.out.println((String)util.getProperty(bean
, "inner.message"));
// intarrayプロパティに格納された配列の1番目の要素にアクセス
util.setProperty(bean, "intarray[1]", new Integer(1234));
System.out.println((Integer)util.getProperty(bean
, "intarray[1]"));
// tableプロパティに格納されたMapインスタンスの
// キーhogeで参照される要素にアクセス
util.setProperty(bean, "table(hoge)", "fuga");
System.out.println((String)util.getProperty(bean
, "table(hoge)"));
System.out.println("----");
// beanの全プロパティのうち、bean2にも存在する
// プロパティに値をコピー
// この例ではfooプロパティの値がコピーされる
util.copyProperties(bean2, bean);
System.out.println((String)util.getProperty(bean2, "foo"));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
} |
実行結果
bar
foobar
1234
fuga
----
bar |