CalendarとDate
今まで通っていた単体テストが、今日になって突然失敗するように。問題のコードは、古いファイルを消す処理で、今日から6か月前を求めるメソッドのテストだったんだけど、メソッド自体は、
calendar.add(Calendar.MONTH, -6);
で、単体テストの方は、今日現在の日付を元に、以下のコードと、テスト対象のメソッドとで結果が一致するかというテストが実装されていた。
date.setMonth(date.getMonth() - 6);Dateを無理矢理使ってテストという発想は面白いけど、現在の日付を使うのはだめだよね。テスト結果が環境に左右されてしまう。それにDate.setMonth()は引数の月には0以上しか許していないし。というかなんで今まで通っていたんだ、と思ったら、Dateクラスは負の月を設定すると、ちゃんと年を戻して対応するようだ。
となるとなんで今日になって失敗したんだろう。
Date date = DateFormat.getDateInstance().parse("2007/5/31");
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
date.setMonth(date.getMonth() - 6);
calendar.add(Calendar.MONTH, -6);
System.out.println(date);
System.out.println(calendar.getTime());
Fri Dec 01 00:00:00 JST 2006 Thu Nov 30 00:00:00 JST 2006
ふ〜ん。6か月前は、11/31日になるけど、11月に31日は無いから、どちらかにずらすわけだ。Dateは12/1に、Calendarは11/30にずらすんだね。こんなのDateからCalendarを呼ぶようにしているのかと思ったら、別々にロジックが実装されてるんだ。
HTTP GETリクエストにおけるパラメータの文字コード
なんか面倒なことになっているな。とりあえず現段階での調査結果をメモ。
サーブレット仕様を厳密に解釈すれば、setCharacterEncoding()は、ボディ部しか規定しないので、GETリクエストにおけるパラメータは関知しない。
RFC2396では、URIでのキャラクタエンコーディングを規定していない。It is expected that a systematic treatment of character encoding within URI will be developed as a future modification of this specification.と言っている。
W3Cでのrecommendationによると、URIでの属性値は、UTF-8の使用が"recommend"されている。でも現実には、携帯端末のように資源が乏しい環境では、UTF-8は使用できないかもしれない。
サーブレットコンテナが、URIのキャラクタエンコーディングとして何を使うかは、サーブレット仕様には書かれていない(見つからなかった)。
Tomcatでは、server.xmlのConnector要素で、useBodyEncodingForURI="true"を指定することで、setCharacterEncoding()の設定をURIにも適用する(独自の対応)。
Jetty-6.1.3では、URIのキャラクタエンコーディングをJetty独自の方式で指定できる。
1) システムプロパティにキー名"org.mortbay.util.URI.charset"でエンコーディングを指定。 2) ServletRequestに"org.mortbay.jetty.Request.queryEncoding"というキー名でエンコーディングを指定。 3) 指定しないとデフォルトはUTF-8になる。
最初に考えたのは、サーブレットフィルタを使用して、ボディ部はsetCharacterEncoding()で変換、URIは自分で変換とする方法。しかしこれはサーブレットコンテナが、上記のサーブレット仕様を厳格に実装していることが前提になる。サーブレットコンテナによっては、setCharacterEncoding()の指定がURIのエンコーディングにも影響するものがあるようだし、それに上記のTomcat/Jetty独自設定が、配備先のサーバに対して行われているかもしれないし、いないかもしれない、よってこの方法をとったアプリケーションは、可搬性が大きく損われる。
さて、となると、現段階での結論は、インハウスアプリケーションなら、使用するサーブレットコンテナと相談。可搬性を重視するなら、昔のようにsetCharacterEncoding()を使用せずに、サーブレットフィルタで全て自分で変換する、かなぁ? でも、この時のエンコーディングに何を使うかが、問題だ。Jettyは何も指定しないとUTF-8になってしまうし。サーブレット仕様に規定が無いんじゃ、結局サーブレットコンテナに依存せざるを得ないんじゃないか?








