code up

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

SAStrutsとかSeasar2の注意点

引き継いだプロジェクトがSeasar2で開発されていた。活発だった当時(数年前)であれば良かったのかもしれないけど、今では使えば使うほどよく分からないフレームワークだと感じる。

理由はこれにつきる: ドキュメントが整備されていない。

Wikipediaには「設定よりも規約」という概念のサポートである。とあるが、明文化されていない規約によって発生する不具合を何度か経験した。また明文化されていてもチーム開発に向いていない制約/仕様も存在するように思う(後述するS2JDBCの仕様など)。

はじめてDIコンテナと呼ばれるものを使用したのはずいぶん昔。ATG Dynamoという今はOracle(ほとんどの製品はOracleのものになっていくなー・・・)の製品。当時はIoCなんて言ってた。この時から他の人にDIを説明する時に、そのメリットを実用的な側面から説明できなかった(概念としての特徴は説明できるが)。今でもそう、DIに対してはかなり懐疑的な立場。テクノロジー、コンセプトとしてはとても高尚なものだと理解しているが、メンバーの入れ替えも多く、知識やレベルの異なるメンバーで構成されるチーム開発を任される立場としては予算、スケジュール、品質を達成するために必要だ、あるいは導入すると効果的だ、という結論にはどうしても至らない。本当に理解して活かせるようになるまでの習得コストも高いと考えている。もっと別のこと(RESTとかWebSocketとかビッグデータとかOAuthのような既存のテクノロジーをイノベーションする事)の学習に力を注いだ方が良いのではないか、と思う。

そんな流れがあったのかどうかは存じ上げないが、S2プロジェクト自体が途中で投げ出された感があるので仕方ない状態なのだろうか。Amazonで本を買う、メーリングリストに入る、ソースコードを直接見る、という選択肢があるように思うが、メーリングリストはあの「どうか教えて下さい」的な雰囲気が苦手。MLで回答された有益な内容がドキュメントに反映される流れがあればいいのに、と思う。結局はリポジトリから全てのソースコードをダウンロードしておいて都度参照している。

これからもしばらく付き合わなければいけないので、忘れそうな注意点などを書いておく。

S2JDBCは使わない
その1。Where句の組み立て(?)でオブジェクトをつなげて「流れるように」構築できるらしいが、とあるひとつの(私にとって)致命的な仕様が問題であるため、引き継いだ時点で使っていたS2JDBCを全てDbUtilsに置き換えた。その仕様とは、
上記のサンプルでは、"A"や"1"のように直接リテラルを渡していますが、変数を渡した場合、変数がnullの場合は、条件に含まれなくなります。
nullを渡してしまった場合、エラーともならず、a = nullで検索して結果が返ってこないわけでもなく、単に条件から除外してしまうため、意図しない結果が返ってきてしまう。加えてSQL文(外だしのSQL?)でもif句が書けることによって同様の問題が発生する可能性がある。あらゆる箇所にこの可能性があったため、全て捨て書き直す必要に迫られた経緯がある。
その2。BLOBをサポートしていない。動画や音声を扱うアプリが増えてくる中、これは残念な仕様。
※ S2DaoもDBFluteもそうだが、2-Wayとかデータを消してテーブルを作り直すとか(片方だけ使えば、とかテストデータは別に作っておくものだ、という言い分もあるだろうが)、リスクの方が大きい気がしてならない。

トランザクション管理(S2Tx/JTA)は、DbUtilsとうまく連動してよく動いて頂いております
S2Axis2は使わない
Webサービスとして使う場合は分からないけど、RESTサービスを公開するためのライブラリとして使うには足りない。例外発生時にXMLの応答を返してしまうとか。本家と同様、オリジナルの開発者は別の事に夢中で放置したままとか。Seasarプロジェクトを見ていると日本(日本語ベース)のオープンソースはやっぱり寿命が短いなぁ、と思う。こちらもJerseyを使う方向にようやく持っていくことができた。
SAStrutsの注意点
そもそもドキュメントが足りない気がする。s:link, s:formなどの<%@ taglib prefix="s" uri="http://sastruts.seasar.org" %>の説明が公式サイトで見つけられなかった。
  • SAStrutsでActionForm@Resourceをつけてもインジェクトされない ※ FormCreatorによってAutoBindingNONEに指定されているから
  • ActionFormHttpServletRequestを扱うときは、multipartな送信の場合、取得するタイミングによって異なるオブジェクトになる。取得するタイミングが早すぎるとgetParameterで値が取れない。コンストラクタで予め取得しておく、といったことはぜすにRequestUtil.getRequest()で都度取った方がよさそう
  • intなどのプリミティブフィールドには@Requiredはつけない。効かないため ※ 全部Stringでといった方針は取っていない
  • 画面から入力のある項目のみpublicとし(でないと受け取れないため)、それ以外はpublic以外とする(そうすると受け取らないため)
  • Action/ActionFormのフィールドをrequest.setAttributeでセットするのでActionのフィールド名、Formのフィールド名、requestまたはsessionにセットする変数名は重複しないようにする。nullやプリミティブ型が絡むと不可解な(内部を知らないと説明できないような)動きをする
  • javax.servlet.ServletException: javax.servlet.ServletException: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number
    Actionクラスにて親クラスのメソッドを実行中にそのメソッドがActionMessageExceptionを出した時発生。親クラスのそのメソッドの可視範囲がpublicだったのが悪かったみたい。protectedに変更したら直った。
  • redirect=trueは最後に付ける。制約というよりはフレームワーク側でカバーして欲しいところ
  • クラスを操作しているからだろうけどfinalをつけるとやたら怒られる
  • ActionFormを複数のActionで使い回すことは(かろうじて)可能。JSPも表示するだけであればAction間で共有できるが、s:formとかを使おうとするとフォルダ名がActionクラス名に合ってないとダメみたい。ActionForm名はクラス名(大抵の場合パスカル形式; FooForm)のキャメル形式名(fooForm)で定義しないと自動設定に失敗する。
    public class FooAction {
    
        @ActionForm
        @Resource
        private CommonForm commonForm;
    
        @Execute(validator = false)
        public String index() {
            return "/foo/foo.jsp"; // フォルダ名はActionに合わせた方が無難
        }
    }

使い手を選ぶというか、ある程度(Seasar2で)失敗をした人がようやく使い方を学んで、使いこなせるようになるのではないかと思う。外注先が「フレームワークにはSeasar2を使います。」といって、それまでSeasar2を使った実績がない(今回はこのケース)場合、次は絶対に断ろうと思う。逆に弱点を十分知っていて、それ以外のフレームワークは勧めません、という場合には適切だと思う。

関連記事
タグ:SAStruts Seasar2
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。