yohjizzz's Blog

I'm a Programmer.

パラメータでフィールド値上書きしちゃうよ、の件

リクエストパラメータでアクションのDI用のフィールドを上書きできてしまう罠という話。
最初から考慮されていなかったのがちょっと不思議な感じ。
 ・
 ・
 ・
ともあれSAStrutsを使う場合の回避策としては以下のいずれかということになるんでしょうか。

  • リクエストパラメータを受けるときはアクションのpublicフィールドは使わずにアクションフォームを使用する(要は必ずアクションフォームを作る)。
  • アクションにpublicフィールドを作ってもいいけど、DI用のフィールドはpublicにせず@Resourceアノテーションをつける

SAStrutsを実戦投入する際には気をつけないといけませんねー。

新・たけぞう瀕死の日記 - SAStrutsのアクションのpublicフィールド

これは Teeda にも同じようなことが言えますね。
むしろ SAStruts であれば、

  • パラメータをバインドするならアクションフォームに。
  • DI専用のフィールドなら @Resource を。

っていう対応で逃げれるけれど、
Teeda だとアクションフォームに該当する「逃げ道」がないので、
各ページ間で引き継ぐ為の情報を各 Page クラスにフィールド定義していて、
@Subapplication でキャッシュしていたりすると、
デフォルトの設定では、フィールド名のパラメータ(GETでもPOSTでも)を送信すれば値が書き変わってしまいます。

これについては以前MLに問い合わせたところ、
下記の方法↓↓でパラメータを自動バインドさせなくすることはできるのですが、
これだとすべての Page クラスでGET、POST問わず、パラメータがバインドされなくなってしまいます。

  <component class="org.seasar.framework.container.creator.PageCreator">
    <property name="externalBinding">false</property>
  </component>


Page クラスのフィールドに対して、こんな感じ↓の指定ができれば良いんだけど。

    /**
     * BindingType.NONE との異なり、
     * Page 間でのスコープ情報は引き継ぐけど、外部(HTTP GETやPOST)パラメータは受け付けません。
     */
    @ReadOnly
    public String price;


現状、これに対応するには、入力系の Page クラスでバインドした情報を、
後続の Page クラスにそのまま引き継ぐのではなく、1度、別の DTO などに移し替えておいて、
後続の Page クラスはそちら(←DTO)を参照して、表示やDB保存をしないといけない><

追記

@Binding(bindingType=BindingType.NONE)で Seasar2 による自動バインディングを抑止できます.

パラメータでフィールド値上書きしちゃうよ、の件 - ようじのにっき - コメント

BindingType.NONE をフィールド(またはセッター)に指定しまうと、
そもそも以前の Page クラスで設定されたスコープ情報も引き継がれないから、
Teeda に頼らず自分でリクエストやセッションのオブジェクトを参照しないといけないので、
それはそれでなんかちょっと違うかなって気がします。