struts の validwhen では、小数付きの数値比較が正しく行われない。
ソースを追ってみたところ、ValidWhenParser クラスで比較処理をしていたのだけど、これが int 型で比較できる場合は数値として比較、それ以外はすべて String で比較するという処理になっていた。えー、整数だけですか。全然かゆいところに手が届いていない!
これのタチ悪いところは、小数値であっても比較処理自体は行われる点。そう、文字列として比較して、その結果たまに正しい結果を返してしまう。厄介だ。
例えば、start と end という数値入力するフィールドがあって、その大小関係が逆転しないように入力チェックをするとき、
((start == null) or (*this* <= end))
と validwhen 式を書いて、
private String start = "9.5"; private String end = "11";
とすると、文字列での比較となり、1より9の方が後になるってんで、大小関係が正しいにも関わらずエラーとして検証に引っかかってしまう。
private String start = "2.5"; private String end = "5";
という場合は、小数があっても正しい検証結果を返すので、問題なし。こんな感じで一見すると正しく動いているようにみえるので、むーって感じ。ハマリました。
そんなわけで、validwhen は整数の比較と、文字列の比較のときのみ使用するようにしなくちゃいけないです。いや、もう文字列に限定して使用するものだと捉えた方が良いかもしれない。そして数値比較用には、自前で検証メソッドを作成してしまった方が、間違いがなくて良さそう。(または ValidWhenParser の処理そのものを小数対応に直しちゃうのもアリ)
BigDecimal で比較、いやせめて Double で比較してくれれば良かったのに…。
Posted by dT by 16:31 | Comments (0) | TrackBacks (0)
Tiles Hack だなんて大げさだ。
Struts の Tiles プラグインの挙動を変更したくなった。動的に definition を追加したい。どこから手を付けて良いものか悩んでいたのだけど、DefinitionsFatory を自作のものに変更できることが判明したので、これで対応した。
struts-config.xml で Tiles プラグインを設定している箇所で、definitions-factory-class プロパティに、自作の Factory クラスを指定してあげるだけ。
<plug-in className="org.apache.struts.tiles.TilesPlugin">
<set-property property="definitions-factory-class" value="com.deftrash.struts.OriginalI18nFactorySet" />
<set-property property="definitions-config" value="/WEB-INF/tiles-defs.xml"/>
<set-property property="moduleAware" value="true"/>
</plug-in>
definitions-factory-class を指定しない場合は、デフォルトで、org.apache.struts.tiles.xmlDefinition.I18nFactorySet が使用される。tiles-defs.xml を読み込んで、ComponentDefinition を生成するクラスだ。
動的に definition を追加するために、自作 Factory を、この I18nFactorySet を継承して作成。createDefaultFactory メソッドをオーバーライドして改造することにした。
/* (非 Javadoc)
* @see org.apache.struts.tiles.xmlDefinition.I18nFactorySet#createDefaultFactory(javax.servlet.ServletContext)
*/
protected DefinitionsFactory createDefaultFactory(ServletContext servletContext)
throws DefinitionsFactoryException, FileNotFoundException {
DefinitionsFactory factory = super.createDefaultFactory(servletContext);
// TODO 動的にComponentDefinitionを追加する処理をここに
return factory;
たったこれだけで、望むべき動作が得られました。動的に definition を追加する以外のニーズがあっても、ここを起点にいくらでも改造できそうな感じ。まあ、I18nFactorySet クラスで xml を読み出すところが private になっているのが、扱いづらいけど。
すでに struts は枯れて細かいところまで見ずにいたけど、実際に手を入れていこうとすると、改造しやすいように窓口が開いていて、風の通しがすごい良いことに気付く。こういう懐の深いデザインは、見習っていきたいですね。
Posted by dT by 16:40 | Comments (0) | TrackBacks (0)