入れ子構造のBean の中の Obejct を取得する(1)

入れ子構造のクラス、例えば以下のようなクラス、
(setterやgetterなどはここでは省略)

public class Aunit{
	private int id;
	private String name;
	private Bunit bunit;
}
public class Bunit{
	private String name;
	private Cunit cunit;
}
public class Cunit{
	public int id ;
	public String name;
}

書いているロジック内、先頭のクラスのインスタンスだけ持っていって、
一番下の階層のクラスインスタンスを抽出するのは、getterメソッドのチェインを書かなくてはならないか、
いちいち1つ1つ宣言とgetter による取得を書かなくてはならない。

フィールド数が多いと見るのも厭になるし、3階層、4階層とネストが深くなる設計をされると、
非難の的であろう。

タイプセーフではないし、配列、リスト、マップでは使えないが、
以下のような簡単なユーティリティを用意する。

( org.yipuran.util.Fieldgetter :
yipuran-core/Fieldgetter.java at master · yipuran/yipuran-core · GitHub
を使ってる。)

import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import org.yipuran.util.Fieldgetter;

/**
 * GenericGetter
 */
public class GenericGetter{
   private List<String> nlist;

   private GenericGetter() {
      nlist = new ArrayList<>();
   }
   public static  GenericGetter of() {
      return new GenericGetter();
   }
   public GenericGetter with(Supplier<String> s) {
      nlist.add(s.get());
      return this;
   }
   public GenericGetter with(String s) {
      nlist.add(s);
      return this;
   }
   @SuppressWarnings("unchecked")
   public <T, R> R get(T t) {
      Object o = t;
      for(String s:nlist) {
         o = Fieldgetter.of(e->s).apply(o);
      }
      return (R)o;
   }
}

ちょっと大胆な名前だけど、サンプルなので、ご勘弁。

Aunit a = new Aunit();
//  Aunit 内をセットした後で、、、

int id = GenericGetter.of()
      .with(()->"bunit")
      .with(()->"cunit")
      .with(()->"id")
      .get(a);

String cname = GenericGetter.of()
      .with("bunit")
      .with("cunit")
      .with("name")
      .get(a);

with 順番で指定しなければならないが、パスとして確実な指定はできる。

今回は、フィールドの宣言名称を参照していく方法で、プロジェクトのコーディング規則、命名規則
影響を受けやすい。

つぎは、フィールドの宣言名でなく、クラス定義、型で参照する方法を考える。。