良いコ-ドへの道―普通のプログラマのためのステップアップガイド

第5回 メタプログラミング―Excelを使ったDSLを作ろう―その4 Step3:リフレクションAPIで変換ルールを動的に適用する

この記事を読むのに必要な時間:およそ 4.5 分

Step3:リフレクションAPIで変換ルールを動的に適用する

Step3ではいよいよ読み取ったデータの変換処理を組み込みます。変換ルールはデータ項目に応じて異なるので,リフレクションAPIコラム参照を使用して動的に変換処理を適用する必要がでてきます。

下ごしらえとして,変換ルール用のConverterというインタフェースを用意し,変換ルールごとにConverterを実装するクラスを用意しますリスト3~6)。ここでは,IntegerConverter,DateConverter,TrimConverterの3つのクラスを作成しました。これらはStep1のstaticメソッドtoInteger,toDate,trimの処理をクラス化したものになります。

次に,Excelの設定ファイルに「変換ルール」列を追加します表3)。変換ルールには適用したい変換クラスのクラス名を指定します。

最後に,動的に変換オブジェクトを生成して実行するコードを追記しますリスト7)。

で設定ファイルの「変換ルール」列に記述されたクラス名を取得しています。

そして,が一番のポイントです。おーこわ注2。リフレクションAPIでクラス名の文字列から動的にClass型のオブジェクトを取得し,newInstanceメソッドでオブジェクトを生成しています。newInstanceメソッドは引数なしのコンストラクタを呼び出して,オブジェクトの生成を行います。つまり,のコードは次のコードと同じ意味になります。

Converter converter = new IntegerConverter();

リフレクションAPIを使用することで,コードに「具体的なクラス名やメソッド」を書くことなく,動的にプログラムを実行できるようになりました。今後,変換クラスの種類が増えていっても,Step3のコードは書き換える必要がありません。

注2)
「ガリガリガリクソン」でググってみてください。

リスト3 Step3:変換ルール用のインタフェース

public interface Converter {
    Object convert(Object value);
}

リスト4 Step3:変換ルール実装クラスIntegerConverter

public class IntegerConverter implements Converter {
    public Object convert(Object value) {
        return Integer.parseInt(value.toString());
    }
}

リスト5 Step3:変換ルール実装クラスDateConverter

public class DateConverter implements Converter {
    public Object convert(Object value) {
        try {
            return new SimpleDateFormat("yyyyMMdd")
                .parse(value.toString());
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
}

リスト6 Step3:変換ルール実装クラスTrimConverter

public class TrimConverter implements Converter {
    public Object convert(Object value) {
        return StringUtils.trim(value.toString());
    }
}

リスト7 Step3:リフレクションAPIを使用したコード

private static class MessageParser {
...
    public void parse() throws Exception {
        while (index < bytes.getLength() - 1) {
            Map<String, Object> record =
                new HashMap<String, Object>();
            for (int i = 0; i < config.getRowSize(); i++) {
                DataRow row = config.getRow(i);
                String name =
                    (String) row.getValue("データ名称");
                int length =
                    ((BigDecimal) row.getValue("バイト数"))
                    .intValue();
                String ruleClassName =                  ┓
                    (String) row.getValue("変換ルール");  ┛①
                String value = getString(length);
                Class<?> clazz = Class.forName(ruleClassName);    ┓
                Converter converter =                             |
                    (Converter)clazz.newInstance();               ┛②
                Object newValue = converter.convert(value);     ―③
                record.put(name, newValue);
            }
            System.out.println(record);
        }
    }
...
}

表3 Excel設定ファイル(変換ルールを追加)

Noデータ名称長さ変換ルール
1送信日8gcw.gcw5.converter.DateConverter
2ユーザ名10gcw.gcw5.converter.TrimConverter
3メールアドレス20gcw.gcw5.converter.TrimConverter
4ポイント5gcw.gcw5.converter.IntegerConverter

COLUMN JavaのリフレクションAPI

リフレクションAPIとは,JavaのClassオブジェクトを通して,フィールドやメソッド,アノテーションなどのメタ情報を取得することができるAPIのことです。

Javaでメタプログラミングをする際によく使用するリフレクションAPIとして表aのものがあります。

以下の例ではリフレクションAPIを利用して,プロパティ名からゲッタメソッドを実行して戻り値を取得しています注a)。

Employee emp = new Employee(1, "田中一郎");
String[] propNames = {"id", "name"};
for (String propName : propNames) {
    // プロパティ名をメソッド名に変換(name -> getName)
    String methodName = "get" +
        propName.substring(0, 1).toUpperCase() +
        propName.substring(1);
    // メソッド名からメソッドオブジェクトを取得
    Method m = emp.getClass().getMethod(methodName);
    // メソッドを実行
    Object result = m.invoke(emp);
    // 戻り値の値を出力
    System.out.println(propName + "=" + result);
}
注a)
プロパティの取得には,java.beansパッケージ使用した方法もあります。

表a JavaのリフレクションAPI

メソッド名説明
java.lang.Class#forNameクラス名からClassオブジェクトを取得する
java.lang.Class#newInstanceオブジェクトを生成する
java.lang.Class#getConstructorコンストラクタオブジェクトを取得する
java.lang.Class#getMethodメソッドオブジェクトを取得する
java.lang.Class#getFieldフィールドオブジェクトを取得する

著者プロフィール

縣俊貴(あがたとしたか)

学生時代にMSXで制限された環境でのプログラミングの楽しさを学ぶ。以来,オープンソースのWiki実装「MobWiki」の開発や受託開発などを経て,現在はプロジェクト管理ツール「Backlog」,ドローツール「Cacoo」など,コラボレーション型のWebサービスの企画と製品開発を行う。また,Webアプリケーションフレームワーク「Cubby」のコミッタを務める。福岡在住。株式会社ヌーラボ所属。

ブログ :http://d.hatena.ne.jp/agt

Twitter:@agata

コメント

コメントの記入