LoginSignup
3
3

More than 5 years have passed since last update.

Struts2の自動型変換(2014 summer version)

Posted at

自動型変換とは

Struts2には、画面からのリクエストパラメータに対し、自動的にString以外の型へ自動変換する仕組みがあります。これをTypeConvertionと呼びます。

デフォルトで自動型変換を行ってくれる型

自動型変換は、プリミティブ型、配列、java.util.ListなどがStruts2内部で実装済みです。

それ以外にも自動型変換したいけどできる?

Javaのクラスであればすべて可能です。手順は次の通りです。

  • Struts2が提供するStrutsTypeConverterを継承したクラスを作る
  • 型変換するよ!と宣言する

例えばBigDecimalをやってみよう

まず、TypeConverterクラスを継承して、BigDecimal用の型変換クラス、BigDecimalConvertoerを作ります。
継承して、以下の2メソッドを実装していきます。

BigDecimalConverter
public class BigDecimalConverter extends StrutsTypeConverter {
  public Object convertFromString(
    Map context,
    String[] values,
    Class toClass) {
    // 画面→Actionクラス変換
  }

  public String convertToString(Map paramMap, Object paramObject) {
    // 画面←Actionクラス変換(正常系のみ)
  }
}

変換の設定はどこで?

Struts2では以下の2か所で設定できます。どちらかを選びましょう。

  • 特定の型に対してすべて定義する : xwork-conversion.properties
  • Actionクラスごとに定義する : [Actionクラス名]-conversion.properties

ちなみに、Actionクラスごとに定義する方法として、プロパティファイル以外にはアノテーションでも設定可能です。

次の例は、BigDecimal型はすべて変換する例です。

xwork-conversion.properties
# BigDecimal
java.math.BigDecimal=lumi2.converter.BigDecimalConverter

型変換エラーを起こした時は?

作成したTypeConverterクラスのconvertFromStringメソッドにて、次のメソッドを呼ぶと、Struts2内部では「この項目は型変換が失敗したので表示用に元の値を表示する項目」になります。

BigDecimalTypeConverter.java
super.performFallbackConversion(context, paramArrayOfString, toClass);

実装サンプル(BigDecimalConverter)

では実際の実装例です。複数同じ名前のパラメータがリクエストされても対応できるよう、配列チェックをしてから変換しています。

ついでに、カンマ編集をこのクラスで行っています。

BigDecimalTypeConverter.java
public class BigDecimalConverter extends StrutsTypeConverter {

    /**
     * リクエストパラメータからの置換を行う。
     * @param Map コンテキスト情報Map
     * @param String[] パラメータの配列
     * @param Class 変換後のクラス
     * @return 型変換後のパラメータ(オブジェクト)
     */
    @Override
    public Object convertFromString(
            Map context, String[] values, Class toClass) {
        Object result = null;

        log.debug("convertFromString -> " + context + ", "
                + values.toString() + ", " + toClass.getName());

        if (values != null) {
            if (values.getClass().isArray() && toClass.isArray()) {
                Class<?> componentType = toClass.getComponentType();

                result = Array.newInstance(componentType,
                        Array.getLength(values));
                for (int i = 0, icount = Array.getLength(values); i < icount; i++) {
                    Array.set(result, i,
                            convertBigDecimalValue(
                                    context ,
                                    Array.get(values, i) ,
                                    toClass
                            )
                    );
                }
            } else {
                // カンマを取り除く
                result = convertBigDecimalValue(context , values[0] , toClass);
            }
        }
        return result;
    }

    /**
     * BigDecimalへの型変換。
     *
     * @param Map コンテキスト情報Map
     * @param Object 変換対象の文字列
     * @param Class 変換後のクラス
     * @return 型変換した後のオブジェクト
     */
    protected Object convertBigDecimalValue(
            Map context ,Object paramArrayOfString ,Class toClass
            ) {
        BigDecimal result;

        String value = (String)paramArrayOfString;
        value = value.replace(",", "");
        try {
            // Struts2標準で持っているBigDecimal変換
            result = bigDecValue(value);
        } catch (NumberFormatException e) {
            // 型変換エラーをStruts2へ通知する = JSPは変換前を表示
            super.performFallbackConversion(context, paramArrayOfString, toClass);

            return value;
        }
        return result;
    }

    /**
     * BigDecimalからStringへの変換を行う。
     * @param paramMap コンテキスト情報Map
     * @param paramObject Actionクラスのフィールド
     * @return 画面に表示する文字列
     */
    public String convertToString(Map paramMap, Object paramObject) {
        if ( paramObject instanceof BigDecimal ) {
            NumberFormat fmt = NumberFormat.getInstance();
            BigDecimal dec = new BigDecimal(paramObject.toString());
            return fmt.format(dec);
        } else {
            return paramObject.toString();
        }
    }
}

アノテーションで設定する例、Actionクラスごとに設定する例は?

長くなるので分けます(´・ω・`)

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3