読者です 読者をやめる 読者になる 読者になる

reflectionToString で再帰的出力


ToStringBuilder の reflectionToString

たとえばこんなコード

List<Hoge> l = Arrays.asList(new Hoge("S1", 1), new Hoge("S2", 2)); 
Bar bar = new Bar(100, l);

System.out.println(ToStringBuilder.reflectionToString(bar));

以下のような出力が得られる。

etc9.Bar@1a457b6[id=100,list=[etc9.Hoge@b0f13d, etc9.Hoge@ae000d]]

だけどlistの中身がみたい

listの中のオブジェクトなどを再帰的に表示したくないでしょうか?ToStringStyle を拡張することで、reflectionToString の出力形式を簡単に変更できます。指定パッケージのオブジェクトは再帰的に中身を表示するようにしてみます。

public class RecursiveToSrtingStyle extends ToStringStyle {
    private List<String> recursivePackags;
    private int recursiveLimit = 10;

    public RecursiveToSrtingStyle(String... pkgs) {
        super();
        recursivePackags = Arrays.asList(pkgs);
        //this.setUseShortClassName(true);
        this.setUseIdentityHashCode(false);
    }

    @Override
    protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
        for(String packaz : recursivePackags) {
            if (value.getClass().getCanonicalName().startsWith(packaz)) {
                buffer.append(ToStringBuilder.reflectionToString(value, this));
                return;
            }
        }
        buffer.append(value);
    }
    
    @Override
    protected void appendDetail(StringBuffer buffer, String fieldName, Map map) {
        buffer.append(getArrayStart());
        int count = 0;
        for(Entry<?, ?> entry : ((Map<? ,?>)map).entrySet()) {
            appendDetail(buffer, fieldName, entry.getKey());
            buffer.append(getFieldNameValueSeparator());
            appendDetail(buffer, fieldName, entry.getValue());
            appendFieldSeparator(buffer);
            if((count++) > recursiveLimit) {
                buffer.append("...");
                break;
            }
        }
        removeLastFieldSeparator(buffer);
        buffer.append(getArrayEnd());
    }

    @Override
    protected void appendDetail(StringBuffer buffer, String fieldName, Collection coll) {
        appendContentStart(buffer);
        int count = 0;
        for(Object o : coll){
            appendDetail(buffer, fieldName, o);
            appendFieldSeparator(buffer);
            if((count++) > recursiveLimit) {
                buffer.append("...");
                break;
            }
        }
        removeLastFieldSeparator(buffer);
        appendContentEnd(buffer);
    }
}

オブジェクト用、Map用、Collection用の処理をオーバーライドします。

実行

List<Hoge> l = Arrays.asList(new Hoge("S1", 1), new Hoge("S2", 2)); 
Bar bar = new Bar(100, l);

System.out.println(ToStringBuilder.reflectionToString(bar,
    new RecursiveToSrtingStyle("etc9")));//etc9パッケージ以下を再帰出力

以下のような出力が得られました。

etc9.Bar[id=100,list=[etc9.Hoge[foo=S1,var=1],etc9.Hoge[foo=S2,var=2]]]

ばんざい。

おまけに ToStringStyle で定義されている出力結果を。

DEFAULT_STYLE

ToStringBuilder.reflectionToString(bar,ToStringStyle.DEFAULT_STYLE);
ToStringBuilder.reflectionToString(foo,ToStringStyle.DEFAULT_STYLE);
etc9.Bar@7a78d3[id=100,list=[bar, hoge]]
etc9.Foo@ae000d[id=10000,name=Fooo,bar=etc9.Bar@7a78d3,map={Foo=val}]

MULTI_LINE_STYLE

ToStringBuilder.reflectionToString(bar,ToStringStyle.MULTI_LINE_STYLE);
ToStringBuilder.reflectionToString(foo,ToStringStyle.MULTI_LINE_STYLE);
etc9.Bar@7a78d3[
  id=100
  list=[bar, hoge]
]
etc9.Foo@ae000d[
  id=10000
  name=Fooo
  bar=etc9.Bar@7a78d3
  map={Foo=val}
]

NO_FIELD_NAMES_STYLE

ToStringBuilder.reflectionToString(bar,ToStringStyle.NO_FIELD_NAMES_STYLE);
ToStringBuilder.reflectionToString(foo,ToStringStyle.NO_FIELD_NAMES_STYLE);
etc9.Bar@7a78d3[100,[bar, hoge]]
etc9.Foo@ae000d[10000,Fooo,etc9.Bar@7a78d3,{Foo=val}]

SHORT_PREFIX_STYLE

ToStringBuilder.reflectionToString(bar,ToStringStyle.SHORT_PREFIX_STYLE);
ToStringBuilder.reflectionToString(foo,ToStringStyle.SHORT_PREFIX_STYLE);
Bar[id=100,list=[bar, hoge]]
Foo[id=10000,name=Fooo,bar=etc9.Bar@7a78d3,map={Foo=val}]

SIMPLE_STYLE

ToStringBuilder.reflectionToString(bar,ToStringStyle.SIMPLE_STYLE);
ToStringBuilder.reflectionToString(foo,ToStringStyle.SIMPLE_STYLE);
100,[bar, hoge]
10000,Fooo,etc9.Bar@7a78d3,{Foo=val}