JavaBeansとは

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デザインパターン [ エリック・フリーマン ]
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;
}

役に立つと思われる使い方

次回書きます。

関連記事

comments powered by Disqus