SAStrutsで独自の検証用アノテーションを作成する
SAStrutsで既に@Requiredなどいくつかの検証用アノテーションが利用できます。
そこで、それらとは別に独自の検証用アノテーションを作成しようと思ったのですが、
私の探し方が悪いのかSAStrutsのドキュメントなどには記述が見つかりませんでした。
仕方が無いので、SAStrutsのソースコードを追いながら、作成してみたいと思います。
SAStrutsのドキュメント内に記述がありました。以下のリンクの最後のほうを参照です。
id:higayasuo さん、ありがとうございます。
http://sastruts.seasar.org/featureReference.html#Validator
検証用アノテーションクラスを作成する
今回は、郵便番号を検証するアノテーションを作成します。
@Maskを利用すれば実現できますが、まあサンプルということで…
Zip.java
package takehiro.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.seasar.struts.annotation.Arg; import org.seasar.struts.annotation.Msg; import org.seasar.struts.annotation.Validator; /** * 郵便番号かどうかを検証するためのアノテーションです。 * * @author takehiro * */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @Validator("zip") public @interface Zip { /** * メッセージです。 * */ Msg msg() default @Msg(key = "errors.zip"); /** * メッセージの最初の引数です。 * */ Arg arg0() default @Arg(key = ""); /** * 検証の対象となるメソッド名を指定します。 複数ある場合はカンマで区切ります。 * */ String target() default ""; }
@Validator("zip") を指定するのがミソです。引数に指定した "zip" が
このアノテーションを指すキーになります。
検証用メソッドを作成する
次は、実際に郵便番号を検証するメソッドを作成します。
org.seasar.struts.validator.S2FieldChecks を継承して新しいクラスを作成しました。
CustomizedS2FieldChecks.java
package takehiro.validator; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import org.apache.commons.validator.Field; import org.apache.commons.validator.GenericValidator; import org.apache.commons.validator.Validator; import org.apache.commons.validator.ValidatorAction; import org.apache.struts.action.ActionMessages; import org.seasar.struts.validator.S2FieldChecks; /** * Seasar2用の独自検証メソッドです。 * * @author takehiro * */ public class CustomizedS2FieldChecks extends S2FieldChecks { private static final long serialVersionUID = 1L; /** * 郵便番号かどうかをチェックします。 * * @param bean * JavaBeans * @param validatorAction * バリデータアクション * @param field * フィールド定義 * @param errors * エラーメッセージの入れ物 * @param validator * バリデータ * @param request * リクエスト * @return 検証結果がOKかどうか */ public static boolean validateZip(Object bean, ValidatorAction validatorAction, Field field, ActionMessages errors, Validator validator, HttpServletRequest request) { String value = getValueAsString(bean, field); if (!GenericValidator.isBlankOrNull(value)) { final Pattern zipPattern = Pattern.compile("\\d{3}-\\d{4}"); final Matcher matcher = zipPattern.matcher(value); if (!matcher.matches()) { addError(errors, field, validator, validatorAction, request); return false; } } return true; } }
検証用メソッドを登録する
先ほど作成した検証用のメソッドを登録します。
具体的には、validator-rules.xml に登録することになります。
ここで、name属性の "zip" は、アノテーションクラスの@Validatorの引数と同じにします。
また、msg属性の "errors.zip" は、次に追加するエラーメッセージのキーとなります。
validator-rules.xml
…中略 <validator name="zip" classname="takehiro.validator.CustomizedS2FieldChecks" method="validateZip" methodParams="java.lang.Object, org.apache.commons.validator.ValidatorAction, org.apache.commons.validator.Field, org.apache.struts.action.ActionMessages, org.apache.commons.validator.Validator, javax.servlet.http.HttpServletRequest" depends="" msg="errors.zip"/> …中略
エラーメッセージを追加する
郵便番号の検証でエラーが発生した場合に表示するエラーメッセージを追加します。
先ほど書いたように、キー "errors.zip" は、validator-rules.xml の msg 属性と一致させます。
application_ja.properties
errors.zip={0}は郵便番号として不正です。
application.properties
errors.zip={0} is an invalid zip code.
Actionのpublicフィールドに、作成したアノテーションを追加する
今回は、SAStrutsのチュートリアルに含まれる ValidatorAction を利用します。
以下のように、郵便番号を入力するフィールドを新しく追加します。
ValidatorAction.java
…中略 @Required @Zip public String zip; …中略 @Execute(validator = false) public String index() { byteText = "1"; shortText = "1"; integerText = "1"; longText = "1"; floatText = "1.0"; doubleText = "1.0"; dateText = "2008/1/1"; emailText = "higayasuo@gmail.com"; urlText = "http://d.hatena.ne.jp/higayasuo"; intRangeText = "7"; longRangeText = "7"; floatRangeText = "7.0"; doubleRangeText = "7.0"; minlengthText = "123"; maxlengthText = "1234567890"; minbytelengthText = "ああ"; maxbytelengthText = "あああああ"; phoneText = "03-9999-9999"; zip = "999-9999"; return "validator.vm"; } …中略
画面(vmファイル)を修正する
validator.vm
…中略 <tr> <td>郵便番号:</td><td><input type="text" name="zip" value="$!zip"></td> </tr> …中略
以上で全ての準備が完了しました。
実際動かしてみる
無事動きました。エラーメッセージもちゃんと表示されます。
まとめ
実際のPJなどでは、今回のように独自の検証を行うケースがあると思うので
今回のような作業がマニュアル化されてると嬉しいですね。
SAStrutsのドキュメント内に記述がありました。以下のリンクの最後のほうを参照です。
id:higayasuo さん、ありがとうございます。
http://sastruts.seasar.org/featureReference.html#Validator
Seasar勉強会 in Sendai が開催されます!
東北デベロッパーズコミュニティから、Seasar勉強会 in Sendai の開催案内が来ました。
イベント案内 | 2008-06-14 (土) Seasar勉強会 in Sendai - 東北デベロッパーズコミュニティ(TDC)
早速、参加の申し込みをしました。
以下、タイムテーブルです。
14:00〜14:10 開催にあたって
14:10〜15:10 S2JDBCについて(ひがやすを様から)
15:20〜17:10 東北でのSeasar事例紹介(各30分ずつ)
17:20〜18:05 SAStrutsについて
18:05〜18:15 閉会&今後の予定について
18:30〜 懇親会
目玉は、Seasarプロジェクトチーフコミッタのひがやすをさんです。
東北デベロッパーズコミュニティ設立総会に参加した時はお話しする機会がなかったので、
今回はぜひともお話出来ればなと思います。
Effective Java Second Edition を入手
待望の Effective Java Second Edition を入手しました。
- 作者: Joshua Bloch
- 出版社/メーカー: Prentice Hall
- 発売日: 2008/05/08
- メディア: ペーパーバック
- 購入: 6人 クリック: 65回
- この商品を含むブログ (42件) を見る
初版と比較して、ページ数としては252から346へ、項目数として57から78へ大幅に内容がパワーアップしております。
初版本の翻訳者である柴田芳樹さんのブログによると、翻訳作業はこれから開始するということで、日本語版が出るのはまだだいぶ先になりそうです。
http://blog.so-net.ne.jp/yshibata/2008-05-16/trackback
新しく追加された項目を中心に早速読み進めて行きたいと思います。
Working Effectively With Legacy Code が届きました
Amazonに注文していた本が届きました。
Working Effectively With Legacy Code
- 作者: Michael Feathers
- 出版社/メーカー: Prentice Hall
- 発売日: 2004/09/22
- メディア: ペーパーバック
- 購入: 8人 クリック: 168回
- この商品を含むブログ (69件) を見る
- PART 1: The Mechanics of Change
- Chapter 1: Changing Software
- Chapter 2: Working with Feedback
- Chapter 3: Sensing and Separation
- Chapter 4: The Seam Model
- Chapter 5: Tools
- PART 2: Changing Software
- Chapter 6: I Don't Have Much Time and I Have to Change it
- Chapter 7: It Takes Forever to Make a Change
- Chapter 8: How Do I Add a Feature?
- Chapter 9: I Can't Get This Class into a Test Harness
- Chapter 10: I Can't Run This Method in a Test Harness
- Chapter 11: Need to Make a Change. What Methods Should I Test?
- Chapter 12: I Need to Make Many Changes in One Area
- Chapter 13: I Need to Make a Change, but I Don't Know What Tests to Write
- Chapter 14: Dependencies on Libraries Are Killing Me
- Chapter 15: My Application Is All API Calls
- Chapter 16: I Don't Understand the Code Well Enough to Change It
- Chapter 17: My Application Has No Structure
- Chapter 18: My Test Code Is in the Way
- Chapter 19: My Project Is Not Object Oriented. How Do I Make Safe Changes?
- Chapter 20: This Class Is Too Big and I Don't Want It to Get Any Bigger
- Chapter 21: I'm Changing the Same Code All Over the Place
- Chapter 22: I Need to Change a Monster Method and I Can't Write Tests for It
- Chapter 23: How Do I Know That I'm Not Breaking Anything?
- Chapter 24: We Feel Overwhelmed. It Isn't Going to Get Any Better
- PART 3: Dependency-Breaking Techniques
- Chapter 25: Dependency-Breaking Techniques
全434ページと、かなりのボリュームです。
ちょっとづつ読み進めて行きたいと思います。
「小飼弾のアルファギークに逢ってきた」を読みました
「小飼弾のアルファギークに逢ってきた」を読みました。
発売直後、近くの本屋を梯子して探したのですが見つからなかったので、結局 Amazon で注文しました。
小飼弾のアルファギークに逢ってきた (WEB+DB PRESS plusシリーズ)
- 作者: 小飼弾
- 出版社/メーカー: 技術評論社
- 発売日: 2008/04/14
- メディア: 単行本(ソフトカバー)
- 購入: 19人 クリック: 834回
- この商品を含むブログ (195件) を見る
大変読み応えがありました。せっかくなので、各章で印象に残ったフレーズをメモ。
#0 Ruby on Rails開発者 David Heinemeier Hansson
David Heinemeier Hansson
我々は、簡単なことをより簡単にしたいと考えています。簡潔なものは簡潔なままに留めておきたいので、成長するに従って会社は当然大きくはなっていくけれど、なるべく少ない従業員でそれを実現したい。
#2 Perl開発者 Larry Wall
Larry Wall
<<(私は)金持ちです。>> どれだけ持っているかではなく、どれだけ与えることができるかというのが金持ちの定義なら。
#3 livedoor 池邉智洋/谷口公一/ma.la
ma.la
土地に制約を受けている人が山ほどいるっていう感じがする。今地方で、ひっそりとコソコソ、何かおもしろいものを、1人で何か核兵器とか作っているような人がたぶんたくさんいるには違いないんだろうけど、そういう人たちが東京にいないと出会えない状況が、すごくもったいないと思う。そういう人は、ネットワークを通じてもうまくつながれないような気がする。それをネットワークが救うかっていったら、今のところあまり救えていない。救えていないから、それをなんとかしないとあれかなぁって。
#4 Twitter Co-founder Evan Williams
小飼弾
ウェブサイトを作るにあたって最も重要なことは? 2.0でなくてもいいので(笑)。
Evan Williams
情熱かな。できると見込んだらやる、という。人を見るときには、技術力よりもその人の持っている情熱に注目している。ウェブはまだ15歳ぐらいで、可能性はまだまだたくさんある。そういうところでは、「それを貫く能力」より「好きを貫く」力のほうがものをいう。「できるからやる」というのは、新しいことをやるには向いていない。
#5 The Seasar Project チーフコミッタ ひがやすを
ひがやすを
すごい技術があって、それに負けたままなんて悔しくないですか? そこは、かなわないからお前に任せたなんて、私は逃げたみたいでいやですね。競い合ってこそ、技術は向上していくんだと思います。Javaは、言語的にはHOT Deployのしくみは提供していませんが、工夫次第で何とでもなる。常に挑戦し続けたいですね。
#6 「達人プログラマー」著者 Dave Thomas
Dave Thomas
ソフトエンジニアというものはありません。少なくともまだないです。どういうことかというと、これ以上削れないところまで削るのがエンジニアリング。これ以上削れないところまで削るということは、どこまで削るとそれが壊れてしまうかというのが分かっているということです。まだソフトウェアに関しては我々はそのレベルには達していないんです。達していないから、まだソフトウェアエンジニアという言葉というのは嘘である。
#7 Pathtraq/Japanize 奥一穂
奥一穂
もう1つはじゃあ最初の母集団が尖っててそもそも問題なのかっていうところで、メディアの価値っていうのはデータを送る人と受ける人の落差なんですよ。そういう意味で言うと、みんなが使っていて、みんなが見たあとのページの情報をとっても実は全然メディアとしての意味がない。統計としては意味がありますけど、たぶんそれだとそんなに需要がない。だからやっぱりできるだけ、まずはニッチな人に使ってもらって、それまでニッチじゃない人にとって便利なツールになる。そういう形で、一番上にいる人たちと、その次の人たちの間でまずコミュニケーションができる。そういうふうにできればいいと思っているので、最初に尖っている人(のログ)が取れているっていうのは正解なんだろうと思っています。逆にそういう形にしないと、一気にマスを狙うっていうのはなかなか難しいですよね、資本的な問題とか、コミュニケーションの問題とか。
#8 Mozilla Corporation/jQuery開発者 John Resig
小飼弾
ただのエンジニアとすごいエンジニアを分けるものは何でしょう?
John Resig
あえて機能を追加しないことができる人がすごいエンジニアだと思います。すなわち具体的に何が重要であり、かつ何が重要でないかということを理解したうえで、その理解のもとで最適化ができる人。
#9 「Binary2.0」「スルー力」提唱者 高林哲
高林哲
「粘り強さ」じゃないですか。「深追い」ってぼくは呼ぶんですけど、問題を解決する場面で、わかるまで調べると。デバッグとかもそうじゃないですか、気分転換して、ぱっとひらめくときもありますけども、自分がしでかしたバグだったらけっこうひらめくこともあると思うんですけど、他人のプログラムって徹底的に調べていかないと…。
小飼弾
もう地の果てまでも。
高林哲
追いかけていかないといけないですよね。そのときにどこまで追いかけるかっていう、忍耐力っていうか粘り強さが必要かなと。ぼくなんかは、今日はもうこれでおしまいと諦めるときがあるんですけど、どんどん追いかける人は地の果てまで行っちゃうんで。たいしたもんだなと思います。
#10 Perl Mongers Ingy dot Net/Dave Rolsky/Jesse Vincent/C.L. Kao
DANKOGAI
「優れたエンジニア」として重要なのはどんなことだと思いますか?
(中略)INGY
プログラマー以外の視点を持つっていうのもものすごい重要。たとえばCLKAOにとっての料理とか、Daveにとっての音楽とか。そうやって外からの視点を持っていると、ちゃんと使う人の意見に耳を傾けられる。
#11 IT戦士 天野仁史/こんにちはこんにちは! はまちや2
小飼弾
多くのユーザが利用するウェブアプリケーションですが、開発する上でもっとも重要なことは?
はまちや2
勢いですね!
天野仁史
あー勢い重要ですね!
はまちや2
何か思いついたら、その日のうちに、実際に動くプロトタイプを作っちゃうくらいの勢い。
小飼弾
作って出しちゃうっていうのは、本当重要だよね。それが本当に肌でわかったのは、ブログを書き出してから。変なクオリティのものを人様に出せるかいではなくて、出してもいいんですよ。人に突っ込まれたらそのときに直せばいい。
SAStruts + Velocity (2)
SAStruts + Velocity が動くことが確認出来たので、今度はSAStrutsの
チュートリアルに含まれるサンプルをVelocityに移植中です。
そこで、移植にちょっと手間取ったサンプルがありました。
「複数選択リスト」サンプルにて
「複数選択リスト」サンプルのJSPファイルは以下のようになっています。
multiselect.jsp
<html> <head> <title>Multiselect</title> </head> <body> <html:errors/> <s:form action="/multiselect"> <html:select property="select" multiple="true" size="3"> <html:option value="1">One</html:option> <html:option value="2">Two</html:option> <html:option value="3">Three</html:option> </html:select> <br /> ${f:h(select)}<br /> <input type="submit" name="submit" value="サブミット"/> </s:form> </body> </html>
まず、toolbox.xml に ListTool の定義を追加します。
toolbox.xml
<tool> <key>list</key> <scope>application</scope> <class>org.apache.velocity.tools.generic.ListTool</class> </tool>
multiselect.vm
<html> <head> <title>Multiselect</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <form name="multiselectActionForm" method="post" action="$link.setRelative("velocity/multiselect/")"> <select name="select" multiple="multiple" size="3"> <option value="1"#if($list.contains($select, "1")) selected="selected" #end>One</option> <option value="2"#if($list.contains($select, "2")) selected="selected" #end>Two</option> <option value="3"#if($list.contains($select, "3")) selected="selected" #end>Three</option> </select> <br /> $!escape.html($!select)<br /> <input type="submit" name="submit" value="サブミット"/> </form> </body> </html>
すると、以下のようなエラーが発生しました。*1
nvocation of method 'contains' in class org.seasar.struts.action.ArrayWrapper threw exception class java.lang.UnsupportedOperationException : contains
何でだろうと思い、ArrayWrapper#contains(Object)の実装を見てみたら、以下のようになっていました。
public boolean contains(Object o) { throw new UnsupportedOperationException("contains"); }
これが原因です。
どうしようかな…、ArrayWrapper#toArray()はサポートされていたので以下のように修正してみました。
修正後の multiselect.vm
<html> <head> <title>Multiselect</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <form name="multiselectActionForm" method="post" action="$link.setRelative("velocity/multiselect/")"> <select name="select" multiple="multiple" size="3"> <option value="1"#if($list.contains($select.toArray(), "1")) selected="selected" #end>One</option> <option value="2"#if($list.contains($select.toArray(), "2")) selected="selected" #end>Two</option> <option value="3"#if($list.contains($select.toArray(), "3")) selected="selected" #end>Three</option> </select> <br /> $!escape.html($!select)<br /> <input type="submit" name="submit" value="サブミット"/> </form> </body> </html>
不恰好なコードですが、とりあえず動きました。
もっとスマートな方法は無いのでしょうか?
*1:SAStruts1.0.2-rc3 では、ArrayWrapper#contains(Object) がサポートされる予定になっています