Commons BeanUtils 1.9.3 のうち BeanUtilsBean#copyProperties() のソースコードを読んだ記録です。この記事をご覧の方はご存知と思いますが、リフレクションを利用してオブジェクトの全プロパティをコピーするメソッドです。
目的
- Optional<T> と T との相互変換に対応していないのでよろしくやらせたい。
- → BeanUtilsBean を継承して手を加えるか同等のものを書き直さないと難しそう。
- @lombok.Builder への書き込みにも対応させたい。1
- → BeanIntrospector を書けば対応可能。
主要クラス
- BeanUtilsBean
- PropertyUtilsBean : プロパティの get / set, PropertyDescrtiptor (メタデータ)管理
- BeanIntrospector : オブジェクトの PropertyDescrtiptor を列挙
- Resolver : 「path.to.value[2]」等の複雑なプロパティ名の解決
- ConvertUtilsBean
- Converter
- PropertyUtilsBean : プロパティの get / set, PropertyDescrtiptor (メタデータ)管理
BeanUtilsBean 以外はいずれもコンストラクタ引数や getter / setter で設定可能です。
シーケンス図 (POJO 同士の場合)
上記の通り、プロパティの読み取り/書き込み自体は PropertyUtilsBean が行います。BeanUtilsBean のやっていることは PropertyUtilsBean / ConvertUtilsBean の呼び出しと一部ログ出力程度です。
- PropertyUtils はリフレクション API の Method クラスを介してプロパティを読み書きします。
- 元の dest, orig にないメソッドは呼ばせられません。
- メソッド名自体は(それに対応した BeanIntrospector を書けば)なんでも良いです。
- Converter が引数に取るのは Class オブジェクトです。
- Type 型ではないので、型パラメータは取れません。
(プロパティの型に当該ジェネリック型のサブクラスを指定した場合は別)
- Type 型ではないので、型パラメータは取れません。
- 読み取り不能または書き込み不能なプロパティは単純に無視されます。
シーケンス図 (DynaBean 同士の場合)
ResultSet 等に利用できる DynaBean というものがあって、こちらを使うと Proxy クラスの get / set メソッドを介してプロパティを読み書きさせられます。
なぜか BeanUtilsBean が DynaBean#get() を直接呼びます。
-
WrapDynaBean はその名の通り通常の POJO をラップしたものですが、これを copyProperties() の引数に与えると下記の通り アンラップした上で POJO と同様のアクセス権限チェックが行われるので注意が必要です。
- WrapDynaBean を継承して元の POJO にないプロパティを追加しても恐らく無視されます。移譲すれば通ると思いますが。
PropertyUtilsBean.java#L1374-1378
// isReadable()
// isWritable() も同様
// Treat WrapDynaBean as special case - may be a write-only property
// (see Jira issue# BEANUTILS-61)
if (bean instanceof WrapDynaBean) {
bean = ((WrapDynaBean)bean).getInstance();
}
-
かつてLombok.Builderのメソッド名を変えるPRもありましたが、お蔵入りになった模様 ↩