7.21. BeanUtil

Java Beansに関する以下機能を提供する。

  • プロパティに対する値の設定と取得
  • 他のJava Beansへの値の移送
  • Java Beansとjava.util.Mapとの間での値の移送

7.21.1. モジュール一覧

<dependency>
  <groupId>com.nablarch.framework</groupId>
  <artifactId>nablarch-core-beans</artifactId>
</dependency>

7.21.2. 使用方法

BeanUtil が提供するAPIを使用して、任意のJava Beansに対する操作が実現できる。

BeanUtilの使用例を以下に示す。

Bean定義
public class User {
    private Long id;
    private String name;
    private Date birthDay;
    private Address address;
    // getter & setterは省略
}

public class Address {
    private String postNo;
    // getter & setterは省略
}

public class UserDto {
    private String name;
    private String birthDay;
    // getter & setterは省略
}
BeanUtilの使用例

幾つかのAPIの使用例を以下に示す。 詳細は、BeanUtilの Javadoc を参照。

final User user = new User();
user.setId(1L);
user.setName("名前");
user.setBirthDay(new Date());

final Address address = new Address();
address.setPostNo("1234");
user.setAddress(address);


// プロパティ名を指定して値を取得する(1が取得できる)。
// 値はgetter経由で取得される。
final Long id = (Long) BeanUtil.getProperty(user, "id");

// プロパティ名を指定して値を設定する(nameプロパティの値が「新しい名前」に変更される)
// 値はsetter経由で設定される。
BeanUtil.setProperty(user, "name", "新しい名前");

// 他のBeanを作成しつつ値の移送する。
// Userのプロパティ名と一致するUserDtoのプロパティに対して値が移送される。
// 値の移送はgetter及びsetterを使用して行われる。
// 移送先に存在しないプロパティは無視される。
// 移送先のプロパティの型が異なる場合は、ConversionUtilにより型変換が行われる。
final UserDto dto = BeanUtil.createAndCopy(UserDto.class, user);

// プロパティの値をMapに移送する。
// Mapのキーは、プロパティ名で値がgetterで取得した値となる。
// ネストしたBeanの値はキー名が「.」で区切られて移送される(Map -> Mapとネストはしない)
// 例えば、address.postNoとなる。
final Map<String, Object> map = BeanUtil.createMapAndCopy(user);
final String postNo = (String) map.get("address.postNo");     // 1234が取得できる。

// Mapの値をBeanに移送する。
// Mapのキーと一致するプロパティのsetterを使用してMapの値を移送する。
// ネストしたBeanに値を移送する場合は、Mapのキー名が「.」で区切られている必要がある。(Map -> Mapとネストしたものは扱えない)
// 例えば、address.postNoとキー名を定義することで、User.addressのpostNoプロパティに値が設定される。
final Map<String, Object> userMap = new HashMap<String, Object>();
userMap.put("id", 1L);
userMap.put("address.postNo", 54321);
final User user = BeanUtil.createAndCopy(User.class, userMap);
final String postNo2 = user.getAddress()
                      .getPostNo();             // 54321が取得できる。

重要

BeanUtilはList型の型パラメータに対応していない。List型の型パラメータを使いたい場合は具象クラスでgetterをオーバーライドして対応すること。

public class ItemsForm<D extends Serializable> {
    private List<D> items;
    public List<D> getItems() {
        return items;
    }
    public void setItems(List<D> items) {
        this.items = items;
    }
}

public class Item implements Serializable {
    // プロパティは省略
}

// 具象クラスでオーバーライドしない場合。
// BeanUtil.createAndCopy(BadSampleForm.class, map)を呼び出すと、
// List型の型パラメータに対応していないため実行時例外が発生する。
public class BadSampleForm extends ItemsForm<Item> {
}

// 具象クラスでオーバーライドした場合。
// BeanUtil.createAndCopy(GoodSampleForm.class, map)が正常に動作する。
public static class GoodSampleForm extends ItemsForm<Item> {
    @Override
    public List<Item> getItems() {
        return super.getItems();
    }
}

7.21.3. BeanUtilの型変換ルール

BeanUtil では、Java BeansオブジェクトやMapオブジェクトから 別のJava Beansオブジェクトにデータ移行する際にプロパティを型変換している。

なお、MapオブジェクトからJava Beansオブジェクトにデータ移行する場合、 Mapオブジェクトのキーに . が含まれていればそのプロパティをネストオブジェクトとして扱う。

型変換ルールについては、 nablarch.core.beans.converter パッケージ配下に配置されている Converter 実装クラスをそれぞれ参照すること。

重要

デフォルトで提供する型変換ルールでは、精度の小さい型へ変換した場合(例えばLongからIntegerへの変換)で、変換先の精度を超えるような値を指定しても正常に処理を終了する。 このため、BeanUtilを使用してコピーする際には、コピーする値がシステムで許容されているかどうかを 入力値のチェック によって事前に検証しておく必要がある。 検証しなかった場合、不正な値がシステムに取り込まれ障害の原因となる可能性がある。

重要

型変換ルールはアプリケーション共通の設定となる。 特定の処理のみ異なる型変換ルールを適用したい場合は、 BeanUtil呼び出し時に許容するフォーマットを設定する を参照し、 特定のプロパティや型に対して Converter 実装を適用し対応すること。

7.21.4. 型変換ルールを追加する

型変換ルールを追加するには、以下の手順が必要となる。

  1. 必要に応じて以下のインタフェースを実装し型変換処理を実現する。
  1. ConversionManager の実装クラスを作成する。 今回は標準の型変換ルールに追加でルールを設定するため、 ConversionManager をプロパティとして持つ、 ConversionManager の実装クラスを作成する。
public class SampleConversionManager implements ConversionManager {

    private ConversionManager delegateManager;

    @Override
    public Map<Class<?>, Converter<?>> getConverters() {
        Map<Class<?>, Converter<?>> converters = new HashMap<Class<?>, Converter<?>>();

        // 標準のコンバータ
        converters.putAll(delegateManager.getConverters());

        // 今回作成したコンバータ
        converters.put(BigInteger.class, new CustomConverter());

        return Collections.unmodifiableMap(converters);
    }

    @Override
    public List<ExtensionConverter<?>> getExtensionConvertor() {
        final List<ExtensionConverter<?>> extensionConverters =
            new ArrayList<ExtensionConverter<?>>(delegateManager.getExtensionConvertor());
        extensionConverters.add(new CustomExtensionConverter());
        return extensionConverters;
    }

    public void setDelegateManager(ConversionManager delegateManager) {
        this.delegateManager = delegateManager;
    }
}
  1. コンポーネント設定ファイルに、 ConversionManager の実装クラスを設定する。

    ポイント
    • コンポーネント名は conversionManager とすること。
    <component name="conversionManager" class="sample.SampleConversionManager">
      <property name="delegateManager">
        <component class="nablarch.core.beans.BasicConversionManager" />
      </property>
    </component>
    

7.21.5. 型変換時に許容するフォーマットを指定する

型変換時には、許容するフォーマットを指定することで日付や数値のフォーマットを解除できる。 例えば、カンマ編集されたString型の値(1,000,000)を数値型(1000000)に変換できる。

許容するフォーマットは、以下の3種類の指定方法がある。優先順位は上に記載したものが高くなる。

7.21.5.1. デフォルト(システム共通)の許容するフォーマットを設定する

フォーマットのデフォルト設定は、コンポーネント設定ファイルに設定する。

例えば、画面上で入力される数値についてはカンマ編集されているものも許容する場合には、デフォルト設定しておくことで個別指定が不要となる。

以下に設定方法を示す。

ポイント
  • コンポーネント名を conversionManagerBasicConversionManager を定義する。
  • datePatterns プロパティに許容する日付及び日時形式のフォーマットを設定する。
  • numberPatterns プロパティに許容する数値形式のフォーマット定義を設定する。
  • 複数のフォーマットを許容する場合は複数設定する。
設定例
<component name="conversionManager" class="nablarch.core.beans.BasicConversionManager">
  <!-- 日付及び日時の許容するフォーマットを指定する -->
  <property name="datePatterns">
    <list>
      <value>yyyy/MM/dd</value>
      <value>yyyy-MM-dd</value>
    </list>
  </property>
  <!-- 数値の許容するフォーマットを指定する -->
  <property name="numberPatterns">
    <list>
      <value>#,###</value>
    </list>
  </property>
</component>

重要

yyyy/MM/ddyyyy/MM/dd HH:mm:ss の用に日付と日時のフォーマットを指定した場合、 日時形式の値も yyyy/MM/dd パース出来てしまうため時間情報が欠落してしまうケースがある。

このため、デフォルト指定では日付のフォーマットのみを指定し、日時形式の項目については プロパティ単位にアノテーションで設定 を使用してデフォルト設定をオーバライドするなどの対応が必要となる。

7.21.5.2. コピー対象のプロパティに対して許容するフォーマットを設定する

特定機能だけ デフォルト設定 を適用せずに異なるフォーマットを指定したい場合がある。 この場合は、コピー対象のBean(コピー元またはコピー先)の該当プロパティに対応したフィールドに対してアノテーションを指定し許容するフォーマットを上書きする。

アノテーションは、コピー元とコピー先のどちらに指定しても動作するが、基本的に許容するフォーマットはString型のプロパティに対応するフィールドに指定するのが好ましい。 なぜなら、フォーマットした値を持つのはString型のプロパティであり、そのプロパティに対して許容するフォーマットが指定されていることが自然であるためである。 もし、コピー元とコピー先の両方に指定されている場合は、コピー元の設定を使用する。

例えば、デフォルト設定では日付のフォーマットを指定している場合で、特定機能のみ日時フォーマットを許容する場合に使用するとよい。

以下に実装例を示す。

ポイント
  • コピー元(コピー先)のプロパティに対応したフィールドに対して CopyOption アノテーションを設定する。
  • CopyOptionの datePattern に許容する日付及び日時のフォーマットを指定する。
  • CopyOptionの numberPattern に許容する数値のフォーマットを指定する。
実装例
public class Bean {
    // 許容する日時フォーマットを指定する
    @CopyOption(datePattern = "yyyy/MM/dd HH:mm:ss")
    private String timestamp;

    // 許容する数値フォーマットを指定する
    @CopyOption(numberPattern = "#,###")
    private String number;

    // setter及びgetterは省略
}

7.21.5.3. BeanUtil呼び出し時に許容するフォーマットを設定する

特定機能だけ デフォルト設定 を適用せずに異なるフォーマットを指定したいが、 OSSなどを用いてBeanを自動生成している場合に プロパティ単位にアノテーションで設定 が使用できない場合がある。 また、特定プロパティのみ異なる型変換ルールを適用したい場合がある。

このような場合は、 BeanUtil 呼び出し時に、許容するフォーマットや型変換ルールを設定し対応する。

以下に実装例を示す。

ポイント
実装例
final CopyOptions copyOptions = CopyOptions.options()
        // timestampプロパティに対して許容するフォーマットを指定
        .datePatternByName("timestamp", "yyyy年MM月dd日 HH時mm分ss秒")
        // customプロパティに対してCustomDateConverterを適用
        .converterByName("custom", Date.class, new CustomDateConverter())
        .build();

 // CopyOptionsを指定してBeanUtilを呼び出す。
 final DestBean copy = BeanUtil.createAndCopy(DestBean.class, bean, copyOptions);