Apache の commons-beanutils
今更、BeanUtils の copyProperties と張りあうつもりもないし、Entity DTO Form などで属性値渡すような
アーキテクチャ(アプリ構成)には、とっくに興味がないのだが、、、
原始的には、面白いところなので、書いてみた。
公開している GitHub - yipuran/yipuran-core: Java application framework から、
Fieldsetter. リフレクションでフィールドに値をセット
Throwable な、関数型インターフェース
とにかく便利な、GenericBuilder を使って以下のように書ける。
同一の属性名、同じ型をコピー先に持つことを前提とした厳格なコピーで
誤りがあれば例外をスロー
import org.yipuran.function.ThrowableBiConsumer; import org.yipuran.function.ThrowableSupplier; import org.yipuran.util.Fieldsetter; import org.yipuran.util.GenericBuilder; public static <R, T> R copy(T t, Supplier<R> s){ GenericBuilder<R> builder = Arrays.stream(t.getClass().getDeclaredFields()) .collect(ThrowableSupplier.to(()->GenericBuilder.of(s)), ThrowableBiConsumer.of((r, f)->{ f.setAccessible(true); r.with(Fieldsetter.of((p, u)->f.getName()), f.get(t)); }), (r, u)->{}); return builder.build(); }
コピー先に同一の属性が宣言されていなくても、存在するものだけはコピーして
そうでないものは無視する寛大なコピー
public static <R, T> R copylenient(T t, Supplier<R> s){ GenericBuilder<R> builder = Arrays.stream(t.getClass().getDeclaredFields()) .collect(ThrowableSupplier.to(()->GenericBuilder.of(s)), ThrowableBiConsumer.of((g, f)->{ f.setAccessible(true); g.with((v, u)->{ try{ Field d = v.getClass().getField(f.getName()); d.setAccessible(true); d.set(v, u); }catch(Throwable x){ } }, f.get(t)); }, (a, b)->{}) ,(v, u)->{}); return builder.build(); }
これは、yipuran-core に入れておいた。