cypher256's blog

Pleiades とか作った

toString

共通の親エンティティに toString を実装し public フィールド値を出力されるようにすれば色々便利です。これは特に S2JDBC のエンティティに限ったことではありません。

@MappedSuperclass
public class AbstractEntity implements Serializable {
    public String toString() {
        return <フィールドの値を連結した文字列>;
    }
}
public class Table1 extends AbstratEntity {
    public Long id;
    public String xxxCd;
    public String xxxNm;
}

Table1 table1 = ・・・;
log.debug("table1の中身:" + table1);
DEBUG 2008/01/01 table1の中身:{id=123, xxxCd=A01, xxxNm=名前}

通常はデバッガを使うので不要ですが、大量のデータを一度に見たり、ログを参照するしかない状況の場合に便利です。元々、toString メソッドがデバッグ用途に用意されたものなので、これはどこでもよくやっていると思います。ただ、<フィールドの値を連結した文字列> は手でやるのは面倒なので、自動生成の選択肢が色々あります。まず実行時に解決する動的なもの。

  • Jakarta Commons ToStringBuilder
  • S2 Beans


次に静的に toString メソッドを生成する Eclipse プラグイン

  • Commonclipse
  • Commons4E
  • JUtils


今回、S2 を使っているので、どうせなら、Beans を使おう(変な使い方ですけど)ということで、こんな。

@MappedSuperclass
public class AbstractEntity implements Serializable {
    public String toString() {
        return Beans.createAndCopy(Map.class, this).execute().toString();
    }
}

ちなみに Commons なら、こんな感じです。

        return ToStringBuilder.reflectionToString(this);


これで、早速動かすとスタックオーバーフロー。。。 というかエンティティは相互参照があるので、そりゃそうですね。Table1 -> Table2 -> Table1 -> Table2 -> のような感じで、toString の呼び出しが無限ループに。結局、ちょっとダサいですが、こんなコードにしました。

public String toString() {
    Map<String, Object> fieldMap = new TreeMap<String, Object>();
    for (Class<?> c = getClass(); c != Object.class; c = c.getSuperclass()) {
        for (Field field : c.getFields()) {
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod)) {
                continue;
            }
            Object value = FieldUtil.get(field, this);
            if (value == null || value instanceof String
                    || value instanceof Integer || value instanceof Long
                    || value instanceof Boolean) {
                fieldMap.put(field.getName(), value);
            }
        }
    }
    return fieldMap.toString();
}