ついつい余計なことを.....
2009.01.26
ハマりました。けどこれ面白い話なのでご報告しましょう。ライブラリの使い方に関する意外な結果なんですよ。
Apache-Commons の PropertyUtils なんですけども、これ結構皆使うライブラリで有名ですよね。もともと Struts が出来たときに、Struts がガンガン reflection を使っていて、そこで作ったライブラリを Commons に別立てで寄付した...というのがこのライブラリの発祥ですから、実績も豊富で歴史も(相対的に)長いものの一つ、ということになります。(ここらへんの臭い話は、別な件でハマったことがあります...「一日2回 Strurs でハマった日」でもどうぞ)
この PropertyUtils に、copyProperties() というユーティリティメソッドがあります。要するに、
PropertyUtils.copyProperties(dest, src);
とやると、dest, src がどういうクラスか、は不問で、とにかく src のプロパティが dest のプロパティにコピーされちゃう...という便利なユーティリティです。
勿論これ、リフレクションを活用して、JavaBeans をコピーする、というのが仕事のユーティリティです。勿論これはこれで非常に有用なのですが、大人数で開発する場合にはちょっと問題がないわけではないのです。
それはですね、このメソッドが
JavaBeans の規約に基づいて、getter/setter を自動で探して、見つかった(利用可能な)setter/getter を使ってプロパティをコピーする
というのが正確な動作、だということです.....逆に言えば、
デフォルトのプロパティを「より便利に」するために、同じメンバにアクセスする「便利なバージョンの setter/getter」を誰かが作っちゃうと、copyProperties でコピーするときに、内部的には同じメンバーに複数回 setter が作用する可能性がある....
ということになるわけです。ですから、
setterが賢いことをしようとして、副作用を起こしてる!
とか、
setter がべき等に動作しない(add動作するとかね)
というケースで、copyProperties() は見つけづらいバグを作ることになります...
これが見つけづらいのはですね、バグ自体が「宣言的」だからかもしれません。手続き的にヘンなことが起きる...というよりも、
二重に宣言されているメソッドがあること
が原因だからです。まあ、これは
copyProperties() を使うよりも、愚直にコピー対象を copy() するメソッドを作る
というのがベストの解法でしょう。便利だから、とついつい使うユーティリティですが、落とし穴はあるものです。
あるいは、第3引数追加で、
copyPropeties(Object dst, Object src, Class baseClass);
なんてあったら便利かも....一応Javaリフレクションの規約では、「このクラスで定義されているメソッド」を取得するのが本筋なので、こっちの「baseClassで定義されたメソッド限定でコピーする」というのがあれば、特に O/R マッピングを使うケースでより使いやすいかもしれません、O/Rマッピングで一般的な GenerationGap パターンとの合せ技になりますね....
投稿者 : 杉浦 こずえ | 投稿日時 : 2009.01.26 11:28





