SiNBLOG

140文字に入らないことを、極稀に書くBlog

Slim3 Source Code Reading No7 Validation

Slim3 Source Code Reading #7 - ChugokuGTUG

に参加してきました!


今回も@ttyokoyama 殿と2人だったので、まったりと進みました。
まぁ、他の方が参加していても、まったり進むのですがw

T.Yokoyamaのブログ: Slim3 Source Code Reading #7


今回はValidationです。
簡単な使い方や種類は公式にあります。
Validation - Slim3

大きく分類すると、以下のような感じ。

必須チェック

  • Required

中身は単純で、nullチェックと空文字チェックだけです。


型チェック

  • ByteType
  • ShortType
  • IntegerType
  • LongType
  • FloatType
  • DoubleType
  • NumberType
  • DateType

こちらも中身は割と単純です。
例えばIntegerTypeだと、こんな感じ。


if (value == null || "".equals(value)) {
return null;
}
try {
String s = (String) value;
Integer.valueOf(s);
return null;
} catch (Throwable ignore) {
if (message != null) {
return message;
}
return ApplicationMessage.get(getMessageKey(), getLabel(name));
}
例外を投げるのは、StackTraceも生成したりするので、処理が重いと聞いたことがあるのですが、どうなのでしょう?
教えて、Javaに詳しい方!

ということで、型チェックのほとんどは上記のような処理です。
ただ、NumberTypeとDateTypeは少し違います。
例外が発生するのを確認しているのは同じですが、Integer.valueOf()の部分が異なります。
それぞれ、以下のクラスを利用しています。

  • NumberType:java.text.DecimalFormat
  • DateType:java.text.SimpleDateFormat

ここで、ついでに話題に出たのがSimpleDateFormatのスレッドセーフ問題
google先生に、SimpleDateFormatについて尋ねると、そのように書いてあるページが出てくるのだ。
ただ、それは随分と古い話のようで、今は違うようだ。
SimpleDateFormat にまつわるぐだぐだ話。 - kameidの備忘録 - Sharpen the Saw!
この記事の日付が2009/03/16。
恐らくSimpleDateFormatがスレッドセーフでは無かったのは、2000年ぐらいの話なのだろう。
それでも、未だにgoogle先生のトップページに来るのはSEO対策も真っ青であるw

また、SimpleDateFormatのparseについて、少し注意する必要があるようです。
@ttyokoyama 殿のBlogに詳しく書いてありますが、"2012-02-1a"は、2012-02-01として認識されます。
この挙動は少し注意してやる必要があるでしょう。
最悪、無視しても良いのかなぁとも思いますが、正規表現チェックを合わせてかけてやるなどすれば、対処できると思います。


範囲チェック

  • DoubleRange
  • LongRange

それぞれ、範囲に収まっているかをを確認しているだけです。


if (value == null || "".equals(value)) {
return null;
}
try {
String s = (String) value;
double doubleValue = Double.valueOf(s);
if (minimum <= doubleValue && doubleValue <= maximum) {
return null;
}
} catch (Throwable ignore) {
}
if (message != null) {
return message;
}
return ApplicationMessage.get(
getMessageKey(),
getLabel(name),
minimum,
maximum);
これらを利用する場合は、型チェックも合わせて利用した方が良いでしょう。
Double.valueOf()で例外が発生するので、エラーにはなりますが、ユーザに通知するメッセージを分けることができないためです。
まぁ、メッセージがいい加減な感じなものの場合は、型チェックせずに範囲チェックでも良いかもしれませんが・・・。


長さチェック

  • Maxlength
  • Minlength

これらも中身は単純で、StringにCastして、lengthを見ているだけです。


if (value == null || "".equals(value)) {
return null;
}
try {
String s = (String) value;
if (s.length() <= maxlength) {
return null;
}
} catch (Throwable ignore) {
}
if (message != null) {
return message;
}
return ApplicationMessage.get(
getMessageKey(),
getLabel(name),
maxlength);


正規表現によるチェック

こちらも中身は単純です。
java.util.regex.Matcherを利用して、正規表現にマッチするか確認しているだけです。


if (value == null || "".equals(value)) {
return null;
}
Matcher m = compiledPattern.matcher((String) value);
if (m.matches()) {
return null;
}
if (message != null) {
return message;
}
return ApplicationMessage.get(getMessageKey(), getLabel(name), pattern);


以上で、Validationは終わりです。
後、Controller周りで話題に上がったのが、IndexControllerを指定する時はPathの最後に"/"が必須であるということ。
"/"無しでもページは表示されるのですが、ログを見るかぎりでは、"/"付きでリダイレクトしているようです。
FrontControllerを読んでいる時に、"/"を探しているような処理があったけど、あれが関係しているのか・・・?