横浜のスカイビル10Fに甘いものが食べられる新しいお店

今月オープンしたばかりのお店があります。これも昨日横浜を歩いていた時に看板にふと目が止まって、一度は通り過ぎたんですけど、もう一度見てみるとNEWの文字が。スカイビルのホームページはまだ更新されていないのかお店の記載がありません。

若い女性にウケるであろうカッコイイ店員さんがいます(笑)肝心の甘いものはちょっと高いですけど、値段相応の価値ありという感じ。お値段はドリンクとセットで1,200円〜。座席数がとても少ないので、混んでいたらアウト。他にもおいしそうなランチがあるようでした。情報をメモってこなかったので、行ったらグルメカテゴリで紹介しようと思います〜。

にしても、スカイビルの10Fにあるお店のランチはおいしそうだった…。特に気になったのがここでも紹介した季彩膳 酔心のランチ。定食の数が豊富でおいしそうでした〜。残念ながら昨日のお昼は事前にファミレスですませてしまったのでスカイビルのランチは次の機会に。そんな事言ってたらお腹すいてきた!

行列のできるホームページの作り方

この間本屋に行った時にこのようなタイトルの本がありました。このタイトルを見て瞬時に思った事。「待ち行列なんて作ってどうするんだか」です(爆)

自分の思考を詳しく考えてみると「ホームページに行列はできないよなぁ。できるとしたら待ち行列か?そしたら、なかなかつながらないホームページってこと!?」となります(笑)それくらいたくさんの人が訪れるホームページという所は間違ってませんけど、タイトルから連想する事がとても素直じゃないですね(笑)

すごく感じが出てて笑った!

  1. http://gansaku.hp.infoseek.co.jp/diary/pumike1.jpg
  2. http://gansaku.hp.infoseek.co.jp/diary/pumike2.jpg
  3. http://gansaku.hp.infoseek.co.jp/diary/pumike3.jpg
  4. http://gansaku.hp.infoseek.co.jp/diary/pumike4.jpg
  • 「パンにカビが生えるのはどうしてだと思う?」「お前が早く食べないからだ馬鹿野郎」
  • 「空から雨が降るのはどうしてでしょう」「予報がはずれたからだよ馬鹿野郎」
  • 「鉄でできた飛行機が大空を飛べるのは…」「お客様の笑顔に支えられているからだよ馬鹿野郎」

答えがチアキらしい!(笑)

今日から再開

ここまでやったんだから、最後まで作ってやるー(>_<)。というわけで、既に作ってあったものを全部破棄!新しく作り始めました。S2Daoのコアには手を入れなくてOKになりました。以前のコアを書き換える方法に代わりS2DaoInterceptorにLogicalDeletionInterceptorをアスペクトします。つまりインターセプターの乗っ取りですな(笑)これで本体のバージョンアップにも柔軟に対応できるはず。setAccessible(true)とかやっちゃってるのがかなーりうさんくさいですが(^^;。というわけでまだアノテーションの値は見てないけれど、delete文がupdate文に書き換わって、指定した値が埋め込まれる所までOK。あとはアノテーションを見てbeanに値を設定するのと、微調整かな。どこに落とし穴があるか分からないけど。

今の所順調で落とし穴無し

deleteメソッドについては技術検証完了。ちゃんと動いてるっ!コードは200行ちょっとと、かなり少なめ。アノテーションに定義された値をbeanにセットする時に、型を判定してる部分がもうちょっと綺麗に書けないかなとS2のコードをあさっていたら、ValueTypeクラスがあるじゃないですか。これ使えばたくさんのifが無くなる〜って思ったらResultSet専用だったorz。というわけで仮実装としては型を判定して自前でキャストするコードがズラリ。たぶん綺麗に書けるはずだから、S2本体とS2Daoのコードを走査中。

指定したクラスのインスタンスを生成して、指定した値で初期化してくれる便利なクラスはどこかな〜ちゃんとプリミティブ型にも対応したやつ(笑)。それがあれば50行減る!

#追記:PropertyDescImpl.convertIfNeed()のおかげで50行減った!リファクタ前の技術検証段階で140行。もうちょっと実装とテストを繰り返したらリファクタの予定〜。

落とし穴キター!

public final String delete_DELETEFLAG = "tstamp,timestamp,null";
なんて書いてどうやってupdate時にnullってアノテーションを取ってくるんだ?と思ったら、DELETEFLAGってサフィックスがつかない単体のアノテーションだったのね!!!どおりでおかしいと思ったんだ(笑)

となるとひとつのDaoの中に物理削除と論理削除のメソッドは混ぜる事ができないって事ですね。まぁ、そんなもんインターフェースを分けるだけだから手間にはならないけど。とりあえず削除機能と更新機能は検証完了。動いてます。すごい汚いコード(笑)アノテーションで指定されたプロパティの型が日付だったらアノテーションで定義されている「削除フラグON」の値は無視されて現在の時刻が埋め込まれます。nullも特殊で'null'じゃなくて、nullが入ります。アノテーションは複数定義できるようにしときます。たぶんフラグと日付を同時に更新っていうのが結構あると思うから。

そもそも需要が…って話は大丈夫。使いたいんだけど無いから作るんですっ。最初は言われたからだったけど、作ってみると意外と便利だったり(笑)

#追記:日付型だったら「フラグON値」を無視しちゃ駄目だ。例えば登録日をnullに更新するっていう論理削除の仕方をする場合もあるから。となるとnullって書いてあったらnullでtimestampって書いてあったら現在の時刻かな。っていうか、文字列で指定するから面倒なんだな。

public final String DELETE_FLAG = "tstamp";
public final String DELETE_FLAG_ON = new Date();
public final String DELETE_FLAG_OFF = null;

これじゃ複数定義できないからもっと駄目じゃん!記述量多くてしょぼーんだし。

public final Object[] DELETE_FLAG = {
    "tstamp",   //更新対象の列名
    new Date(), //論理削除する時に入れる値
    null        //普通の更新をする時の値
};

これならいいなぁ〜。DeleteFlagValue.NOUPDATEみたいな定数を入れると、更新時にはデフォルト値で更新してくれるとか。DeleteFlagValue.TIMESTAMPだと現在の時刻を入れてくれるとか。そっちのほうがいいけど、厳密な型チェックがいるしなぁ。Enum使うとTiger必須だし、タイプセーフEnumにしますか。

public final Object[] DELETE_FLAG = {
    "tstamp",
    DeleteFlagValue.TIMESTAMP,
    DeleteFlagValue.NOUPDATE
};

アノテーションの書き方

public static Object[] DELETEFLAG = {
    "tstamp", DeleteFlagValue.TIMESTAMP, DeleteFlagValue.TIMESTAMP
};

基本的には1つ目の値で指定したプロパティの型に代入できるものしか指定できない。2つ目の値は論理削除する時に挿入される値。3つ目の値は更新処理をする際に挿入する値。nullにすればnullが挿入されるし、new Date()と書けばDate型で入る。特殊なのが2つあってDeleteFlagValue.TIMESTAMPがnew Date()の代わり。将来的にDBから日付を持ってこれるように定数を用意しておいた。今は内部的にnew Date()をやってるだけ。もうひとつは DeleteFlagValue.NOUPDATE。これはDaoの引数で指定されたbeanの値を上書きしないという指定。NOUPDATEになっていれば、引数で渡されたbeanの値がそのまま使われる。アノテーションじゃなくてプログラム側で自由な値を設定したい場合に使う。定義する値を直接使わないなら明示的に定義しなくてもいいとも思ったけど…とりあえず動いてるからこのままで。TIMESTAMPはオマケ。DBから取ってくる実装は今の所作る予定無し。この仕様はON, OFFどっちの値でも指定できる。

アノテーションの引数が2つしか無い場合、更新時にデフォルトの値は代入されません。明示的にデフォルトの値を代入しないようにするには、DeleteFlagValue.NOUPDATEを指定してください。

この1文をドキュメントに入れるだけですむと思った。あとで引数は必ず3つという制約をはずしておこう。すごい気の変わりようだな(^^;

new Date().getTime()とSystem.currentTimeMillis()の違い

new Date().getTime() == System.currentTimeMillis()
結果はtrueでした。JavaDocを見ると厳密には違いがあるようですけど、具体的にどう違うのかはつかめず。たぶんどっちでも欲してる値は取れると思うので、S2に合わせて前者を使おうと思います。

進行状況

  • 組み込み方はS2DaoInterceptorにLogicalDeletionInterceptorをaspectするだけ。
  • 引数がbean単体の場合論理削除・更新共に動作OK
  • 引数が配列の場合(バッチ)の処理は未着手(やんなくてOKらしいけど、後でやる)
  • 複数列の一括更新(アノテーション複数定義)の処理がまだ。すぐできる
  • ソースが美しくないのでリファクタする
  • ドキュメントという名のredme.txtでも書く。時間があればオフィシャルのフォーマットで。
  • AbstractAnnotationHandlerを作って、自作のアノテーションとそれに対する処理を簡単に追加できるような仕組みを作る。…のは不可能ではないけれど需要が見えたらにすることにする。