コメント:0StrutsのActionServletはload-on-startupが必須Struts(S2Struts)を使ったWebアプリケーション開発でのトラブル事例。S2StrutsでWebアプリを作っていたのですが、画面にアクセスした際に、javax.servlet.ServletException:ActionMappingsまたはActionFormBeansコレクションが見つかりませんorg.apache.jasper.runtime.PageContextImpl.doHandlePageException(PageContextImpl.java:858)やjava.lang.NullPointerExceptionorg.apache.struts.taglib.html.JavascriptValidatorTag.renderJavascript(JavascriptValidatorTag.java:367)が発生しました。struts-config.xmlの書き方か、S2Strutsの使い方が悪いのかと試行錯誤すること約半日。特定の画面(JSP)に直接アクセスしたか、別画面からアクション経由で遷移してきたかの違いがありました。エラーが発生したのは直接アクセスした場合だけです。上記スタックトレースからStrutsのソースコードを遡ると、ModuleConfigオブジェクトが生成されていないことがわかりました。以上2点を踏まえると。ActionServletが初期化されているかいないかに原因があると思いつきました。web.xmlを見直してみると。ActionServletのload-on-startup要素がない。その為、Actionが実行されるまでActionServletが初期化されず、Actionを実行せずに画面に直接アクセスすると、ModuleConfigオブジェクトがnullになっていたのでした。対応として、以下のようにload-on-startupを指定すると解決しました。<servlet><servlet-name>s2container</servlet-name><servlet-class>org.seasar.framework.container.servlet.S2ContainerServlet</servlet-class><init-param><param-name>configPath</param-name><param-value>sample/app.dicon</param-value></init-param><init-param><param-name>debug</param-name><param-value>true</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet><servlet-name>action</servlet-name><servlet-class>org.seasar.struts.servlet.S2ActionServlet</servlet-class><init-param><param-name>config</param-name><param-value>/WEB-INF/struts-config.xml</param-value></init-param><init-param><param-name>debug</param-name><param-value>2</param-value></init-param><init-param><param-name>detail</param-name><param-value>2</param-value></init-param><load-on-startup>2</load-on-startup></servlet>S2ContainerServletが先に初期化されるように、load-on-startupの番号を付与する点だけ要注意です。組み合わせ方法についてまとめます。次のようなBeanを永続化します。Enumパターンで実装されています。Enumパターンの説明は割愛します。type;}}---------------------------------------------------このPersonオブジェクトをS2Daoで永続化したい場合、S2DaoにBloodTypeとデータベースのカラム型の対応を教える必要があります。データベースにBloodType等と言うカラム型はありませんし、S2DaoもBloodTypeと言う型は認識していません。これをS2Daoに認識させるには、にorg.seasar.extension.jdbc.ValueTypeを使います。BloodType.valueOf(rs.getString(s));}}----------------------------------------------------このBloodTypeValueTypeでは、データベースの文字列型(CHAR,VARCHAR等)とBloodTypeとを対応付けしています。次に、このBloodTypeValueTypeを使ってPersonオブジェクトとデータベーステーブルの変換を行なうように宣言します。*/}---------------------------------------------------ダイコンファイルに、作成したBloodTypeValueTypeをコンポーネント登録し、PersonクラスにアノテーションVALUE_TYPEでそのコンポーネント名を指定します。最後に、Personを永続化するテーブルです。BloodTypeとデータベースの文字列型が相互変換されるようになります。コメント:0タグファイルにオブジェクト参照を渡す時に実行時例外発生JSP2.0のタグファイルで、タグの利用側からタグにオブジェクトを渡したい場合のトラブル事例。以下のようなタグファイルを作成したとします。配置場所は、/WEB-INF/tagsの下です。%></table>---------------------------------------------------このタグにはList型のオブジェクト参照を渡す必要があります。呼び出し側のJSPは以下です。list="${list}"/>---------------------------------------------------list="${list}"のようにELを使ってタグにListオブジェクトを渡します。このJSPを呼び出せば、page、request、session、applicationの各スコープから、"list"と言う名前の属性を探し出し、HTMLの表として表示されるはずです。jsp.error.beans.property.conversionのような実行時例外が発生します。タグが要求する型Listと、実際に指定されたオブジェクトの型が一致しないと言うのです。タグファイルの書き方or呼び出し側のEL式が間違っているのかとさんざん試行錯誤しましたが、原因はweb.xmlにありました。APIのバージョンが古く(2.3)、ELが認識されていなかったようで、web.xmlの<webapp>要素を以下のように記述することで問題が解消しました。Digesterを使ってXMLファイルをロードする場合、ログ出力設定によっては大量のデバッグログが出力されます。Digesterはログが多くて、アプリの実行速度に支障が出るほどです。これを抑止するには、Log4Jの設定ファイル(log4j.xml、log4j.properties)で、rootカテゴリの出力レベルをINFO以上にしてやれば良いのですが、これだと同じrootカテゴリに出力されている他のログまで影響してしまいます。Digesterだけログ出力を変更するには、カテゴリorg.apache.commons.digester.Digesterを追加し、その出力レベルをINFO以上にすればOKです。下のjarファイルが削除されず、配備解除に失敗する事があります。削除しようとしても削除できません。開発作業の効率化を図る上で問題です。対応としては、Webアプリケーションのコンテキスト定義で、antiJARLocking属性を指定することで、Jarファイルのロックをしないようにします。antiJARLocking="true"></Context>例えば、${TOMCAT_HOME}/webapp/sample/META-INF/context.xmlのようなコンテキスト定義ファイルを作成し、上記記述を書くと良いと思います。弊害として、アプリケーションのパフォーマンスが悪化する恐れがあるようですが、これが致命的なボトルネックになることはないと思います。SourceSafeでの問題。Javaで開発をしていると、よく「.(ドット)」ではじまるファイルやディレクトリが登場します。隠しファイル/ディレクトリとして扱われるので、Javaの世界でも同じ目的で使われるようです。具体的には、Eclipseなんかでは.metadataや.settingsのようなディレクトリに、各種設定や実行ファイルが格納されます。他にもMavenのリポジトリも.mavenです。いったドットファイル/ドットディレクトリを、VSSに格納しようとすると。SourceSafeの構文が不正です。ドットファイルや、ドットディレクトリそのものはVSSに格納できるのですが、ドットディレクトリの下にファイルを格納しようとすると上記エラーになります。Windowsでは、「.(ドット)」で始まるファイルやディレクトリは(基本的に)作成できないので、VSSもその辺を考慮していないのだと思われます。よって、Java開発にVSSは使えません。そのまま使用するのではなく、ラッパクラスで包んで使用したいと言う事が良くあります。{log.debug(message);}:}この実装で問題なのは、ログに出力されるクラス名です。log4j.xmlで。メッセージのように出力されます。ログに出力されるクラス名が、"ログを出力したクラス名"ではなく、"ログのラッパクラス名"が出力されてしまっています。これでは、どのクラスが出力したログなのかがわかりません。Throwable)を使用します。このメソッドの第1引数に、ログのラッパクラス名を指定することで、"ログを出力したクラス名"が出力されるようになります。Loggingでは実現できません。LoggingのLogインターフェースには、上記のようなラッパクラス名(FQCN)を引数に取るメソッドが無いからです。SourceSafeのようなファイルの排他ロックをサポートしています。必要に応じてロックすることができる、と言ったものです。これは両者の考え方の違いですので、どちらが良い悪いではありません。個人的には、ロックは極力使用しないほうが良いと思っているので、Subversionのようにロックに消極的なほうが好みです。プロジェクトの方針によっては、Subversionでもファイルのロックをもっと積極的に行ないたいというケースもありますが、これはSubversionの設定で対応することが可能です。具体的には、configファイルを修正します。Data\Subversion\configにあるはずです。これを2箇所修正します。コメントアウトされているので、コメントを外して有効にする。ような記述を追記する。*は全てのファイルに対してロックを強制します。*.javaなどのようにすることで、特定の種類のファイルだけを指定することも可能です。Subversionに格納されているファイルには適用されません。propsetコマンドを使う必要があります。コメント:0プロフィールAuthor:crossroad関西在住。フリーランスのソフトウェアエンジニア。エレキベース(Rock&Roll)とお酒が好物でございます。