GenericBuilder の強化

Java データエンティティなど、データを表現するインスタンス生成する時に威力を発揮する
ものを作っていた。。これを強化しようと思う。
  (自分はエンティティという単語、DBに限定してしまうような表現が嫌い)
https://github.com/yipuran/yipuran-core/blob/master/src/main/java/org/yipuran/util/GenericBuilder.java

これは生成対象のクラスが、setter を持っていることが条件で with メソッド

public <U> GenericBuilder<T> with(BiConsumer<T, U> consumer, U value)

により、setter を with の引数として BiConsumer に渡すことができた。
setter メソッドさえあれば、、、
メソッド参照、Object::setXxxx を BiConsumer とできたので、この with を簡潔に書けた。

public class Foo{
   public int value;
   public void setValue(int value){
        this.value = value;
   }
}
/////////
GenericBuilder.of(Foo::new).with(Foo::setValue, 16).build();

のように書けた。
しかし、setter を持っていないクラスでフィールドに値をセットするには

Throwable な BiConsumer
(自作 → https://github.com/yipuran/yipuran-core/blob/master/src/main/java/org/yipuran/function/ThrowableBiConsumer.java
を使って、以下のようにしないとならない。

(例)Foo というクラス

public class Foo{
   public int value;
}

Foo の value に int 値 16 をセットして生成

Foo foo = GenericBuilder.of(Foo::new)
.with(ThrowableBiConsumer.of((t, u)->t.getClass().getDeclaredField("value").set(t, u)), 16)
.build();

では、対象フィールドが、public ではなく、private では以下のように長くなってしまう。

Foo foo = GenericBuilder.of(Foo::new)
.with(ThrowableBiConsumer.of((t, u)->{
   Field f = t.getClass().getDeclaredField("value");
   f.setAccessible(true);
   f.set(t, u);
}), 16)
.build();

これは、少し辛い。
新しい関数型インターフェースを定義する。

package org.yipuran.util;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.function.BiConsumer;
/**
 * Fieldsetter
 */
@FunctionalInterface
public interface Fieldsetter<T, U> extends Serializable{
   String get(T t, U u) throws Exception;
   public static <T, U> BiConsumer<T, U> of(Fieldsetter<T, U> function){
      return (t, u)->{
         try{
            Field f = t.getClass().getDeclaredField(function.get(t, u));
            f.setAccessible(true);
            f.set(t, u);
         }catch(Throwable ex){
            throw new RuntimeException(ex);
         }
      };
   }
}

これならば、

Foo foo = GenericBuilder.of(Foo::new)
.with(Fieldsetter.of((t, u)->"value"), 16)
,build();

これで生成クラスが setter を持っていなくても、private フィールドでも
GenericBuilder でビルドできる。
しかしリフレクションが走る分の遅さはある。

この Fieldsetter.of 他にも役立ちそうな気がする。