tamuraです。
JavaBeansが出てきた当初はGUI用だったようです。
GUIアプリを作ろうとしてJFrame
を継承したクラスを作ると「serialVersionUID
がないよ!」という警告が出ますが、これはJavaBeans仕様で作られているからのようです。
現在では、私の周辺ではValueObjectとして使うことが多いです。
JavaBeans Javaで作成された移植可能なプラットフォームに依存しないコンポーネント・モデルで、JavaBean仕様に従う。 再使用可能なコンポーネントを作成できる。 http://otndnld.oracle.co.jp/tech/java/htdocs/java_roadmap/glossary.htm#434709 より引用
JavaBeans(ジャバ ビーンズ)とは、Javaで書かれた再利用可能なソフトウェアコンポーネントまたはその技術仕様のこと。1997年後半に登場。JDKのjava.beansパッケージと共にRAD環境の構築を支援するために作られた。現在ではjava.beansパッケージの技術を活用し、RAD環境の構築に限らずJSP等幅広い用途で利用されている。https://ja.wikipedia.org/wiki/JavaBeans より引用
JavaBeansのルール
ルール1: 引数を持たないpublicコンストラクタが必要
コンストラクタはいくつ存在しても問題ないのですが、 引数を持たないpublicコンストラクタが必要となります。
public class JavaBeansSample {
// このコンストラクタは必須
public JavaBeansSample() {
this.initValue = 0;
}
public JavaBeansSample(int initValue) {
this.initValue = initValue;
}
....
リフレクションを使ってインスタンス化してみます。
Class<TestBean> cls = TestBean.class;
TestBean bean = null;
try {
bean = cls.newInstance();
}
catch (ReflectiveOperationException ex) {
ex.printStackTrace();
}
このインスタンス化の仕組みはライブラリやユーティリティを作るときなどに発揮します。
public class UsefulBeanBuilder {
public static <T> T getBeanInstance(Class<T> cls) throws Exception {
T bean = cls.newInstance();
return bean;
}
}
こんな感じで使います。
TestBean bean = UsefulBeanBuilder.getBeanInstance(TestBean.class);
「え?new
でよくない?」と思うのですが、
ライブラリやユーティリティは呼び出し元のクラス名等が不明な場合があります。
例えばDatabaseの戻り値(1レコード)をBeanに詰め込んで返すライブラリを作りたいときは、
public <T> T executeQuery(String sql, Stirng[] param);
のようなインタフェースが必要になるので、このような引数を持たないコンストラクタが有効になります。
あと、この本によるとなるべくnew
はしないのが良いスタイル、ということです。
インタフェースと実装は分離させておきましょう、ということでしょうか。
Head firstデザインパターン [ エリック・フリーマン ]
ルール2: アクセサメソッドに命名規約がある
JavaBeansのプロパティにアクセスする方法が決まっています。
getter
getterの場合、「get○○
」またはBooleanの場合は「`is○○○」でも大丈夫です。
setter
setterの場合、「set○○
」となります。
getter/setterの生成
IDEなら自動で生成してくれます。
また、lombok
を使うとアノテーションを付けるだけでgetter
と`setterを追加してくれますので、getter/setterを大量に書かなくてすみ、コードの見通しが良くなります。
import lombok.Getter;
import lombok.Setter;
public class TestBean {
/** getterのみ */
@Getter
private String data1;
/** setterのみ */
@Setter
private String data2;
/** getterとsetter */
@Getter
@Setter
private Strign data3;
...
}
getter/setterの取得方法
インスタンス化の時のように、ユーティリティやライブラリなどで使う際に、 クラス情報からgetter/setterを取得する方法があります。
public class TestBean {
@Getter
@Setter
private String data1;
}
....
TestBean bean = new TestBean();
PropertyDescriptor pd = new PropertyDescriptor("data", TestBean.class);
Method writer = pd.getWriteMethod();
writer.invoke(bean, "Test");
Method reader = pd.getReadMethod();
String msg = (String)reader.invoke(bean);
System.out.println(msg)
>> Test
ルール3: シリアライズ可能である必要がある
具体的にはjava.io.Serializable
インタフェースを実装する必要があります。
Serializable
を実装する場合はserialVersionUID
というフィールドが必要になります。
なくてもコンパイル時に自動生成されるそうです。IDEだと自動で計算して出してくれたりします。
これはBeanの作りが変更(例えばプロパティが増減)した場合に、古いバージョンでシリアライズした値を新しいバージョンで誤ってデシリアライズしないようにするためのマーキングだそうです。
自分でJavaBeansをシリアライズすることはないので、固定値の1を入れています。
(アプリケーションサーバでクラスタを組んだ時などはセッション情報として勝手にシリアライズされることもありますが、長期間保持するためにシリアライズを使うことは、私はないです)
また、シリアライズしたくないプロパティはtransient
が必要です。
public class TestBean implements java.io.Serializable {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
/**
* この値はシリアライズ対象
*/
@Getter
@Setter
private String message;
/**
* この値はシリアライズ対象外。
* (別のマシンに持って行っても使えない値のため)
*/
@Setter
private transient File file;
}
役に立つと思われる使い方
次回書きます。