エラー内容の流し方

Posted by mkamo on 2008年7月28日

J2EEで開発しているプロジェクトで,EJB層で検出したエラーチェック内容をvalue objectのプロパティとして流しているのを見かけた.問題点と改善案を示してみる.

まずは現状の説明から.EJB層からの戻り値となるvalue objectでは,EJB層で検出するひとつのエラーに対して,ひとつの~Flgというvalue objectのプロパティを定義している.

public class FooResult {
    private boolean hogeCodeErrorFlg;
    private boolean gehoCodeErrorFlg;

    public boolean getHogeCodeErrorFlg() {
        return hogeCodeErrorFlg;
    }
    public void setHogeCodeErrorFlg(boolean value) {
        this.hogeCodeErrorFlg = value;
    }

    public boolean getGehoCodeErrorFlg() {
        return gehoCodeErrorFlg;
    }
    public void setGehoCodeErrorFlg(boolean value) {
        this.gehoCodeErrorFlg = value;
    }
}

EJB層ではメソッドの戻り値として返すFooResultに対して,エラーがあった場合はそれぞれのプロパティにfalseを,なかった場合にはtrueを設定している.

public FooResult foo(...) throws Exception {
    FooResult result = new FooResult();

    if (validateHogeCode(...)) {
        result.setHogeCodeErrorFlg(true);
    } else {
        result.setHogeCodeErrorFlg(false);
    }

    if (validateGehoCode(...)) {
        result.setGehoCodeErrorFlg(true);
    } else {
        result.setGehoCodeErrorFlg(false);
    }

    /// do something...

    return result;
}

JSP/Servlet層では,このvalue objectのget~Flg()をそれぞれ調べて,falseの場合はエラーを表示している.以下の例ではstrutsのタグを使ってエラーを表示している.

<logic:equal name="fooResult" property="hogeCodeErrorFlg" value="false">
    <%= "hogeコードがおかしいですよ." %>
</logic:equal>

<logic:equal name="fooResult" property="gehoCodeErrorFlg" value="false">
    <%= "gehoコードがおかしいですよ." %>
</logic:equal>

このコードにはいくつかの問題点がある.

まず大きな問題として,エラーの追加という変更に対して非常に弱いということである.EJB層のfoo()メソッドで行うエラーチェックをひとつ増やすと,上で示した3つのコードのすべての箇所で修正が必要である.データ・ロジック・表示の修正が必要と,まさにダメ三冠王である.例えばFooResultではエラー内容をListなどに格納しておき,JSP/Servlet層ではそのListの中身を順番に表示する,といった形にすればデータと表示に関してはエラーの追加による影響を減らすことができる.

次に気になるのはプロパティ名である.boolean型のプロパティ名に~Flg,~Flagなどと名づけるのは基本的にはご法度である.hogeCodeErrorFlgといわれても,エラーがあった場合の値がtrueなのかfalseなのかわからない.実際私は上のコードを書いていて何度かtrueとfalseを間違えてしまった.boolean型のプロパティ名は,is~,has~,can~のどれかの名前にしないといけない,と思っておけば問題ない.例えばisValidHogeCodeやisNotValidHogeCodeといったプロパティ名にしておけば,エラーがあった場合の値がtrueなのかfalseなのかはプロパティ名だけから推測できる.

改善案の一例を以下に示しておく.エラー情報保持用のValidationErrorクラスを定義し,FooResultがリストでエラーを保持できる形にする.なお,この例では簡単のため,エラーメッセージをValidateionErrorのプロパティとして持たせているが,idとエラーの原因となった入力値だけをプロパティに持たせておいて,JSP/Servlet層でそれらの値からメッセージを組み立てるようにした方がよいこともある.

/// なにかしらのエラー情報を持つクラス
public class ValidationError {
    /// エラーの種別を表すID
    private String id;
    /// エラーメッセージ
    private String message;

    public ValidationError(String id, String message) {
        this.id = id;
        this.message = message;
    }
    public String getId() {
        return id;
    }
    public String getMessage() {
        return message;
    }
}

/// エラー情報をリストで保持
public class FooResult {
    private List<ValidationError> errors;
    public FooResult() {
        errors = new ArrayList<ValidationError>();
    }
    public List<ValidationError> getErrors() {
        return errors;
    }
}

EJB層では,エラーがあったときにValidationErrorオブジェクトを生成して,FooResultのerrorsプロパティに追加する.

public FooResult foo(...) throws Exception {
    FooResult result = new FooResult();

    if (!validateHogeCode(...)) {
        result.getErrors().add(
            new ValidationError("error.isNotValidHogeCode", "hogeコードがおかしいですよ.");
        );
    }

    if (!validateGehoCode(...)) {
        result.getErrors().add(
            new ValidationError("error.isNotValidGehoCode", "gehoコードがおかしいですよ.");
        );
    }

    /// do something...

    return result;
}

JSP/Servlet層では,FooResultのerrorsプロパティに格納されているValidationErrorのmessageプロパティを順次表示する.

<logic:iterate id="error" name="fooResult" property="errors">
    <bean:write name="error" property="message"/>
</logic:iterate>

これでエラーチェックを追加する場合でも,EJB層のfoo()メソッドのコードの修正だけで対応できるようになる.



コメントを書く




XHTML: 次のタグが使用できます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Please note: 投稿されたコメントが表示されるにはいくらかの時間がかかります.投稿後直ちに表示されませんが投稿ボタンを何度も押さないようお願いします.