1. 無料アクセス解析

crossroad's Blog

Javaを中心にした技術ネタなど。

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
  1. --/--/--(--) --:--:--|
  2. スポンサー広告

S2StrutsのAutoStrutsConfigRegisterPluginの定義順に注意

S2StrutsのAutoStrutsConfigRegisterPluginで

2006-09-26 11:29:26,156 ERROR [http-8080-Processor23] (ApplicationContext.java:675) - action: null
java.lang.NullPointerException
 at org.seasar.struts.config.AutoValidationRegister.registeredValidation(AutoValidationRegister.java:92)
 at org.seasar.struts.config.AutoValidationRegister.registerForm(AutoValidationRegister.java:75)
 at org.seasar.struts.config.AutoValidationRegister.registerValidation(AutoValidationRegister.java:58)
 at org.seasar.struts.config.AutoValidationRegister.register(AutoValidationRegister.java:47)
 at org.seasar.struts.plugin.AutoStrutsConfigRegisterPlugIn.regist(AutoStrutsConfigRegisterPlugIn.java:94)
 at org.seasar.struts.plugin.AutoStrutsConfigRegisterPlugIn.init(AutoStrutsConfigRegisterPlugIn.java:83)
 at org.apache.struts.action.ActionServlet.initModulePlugIns(ActionServlet.java:869)
 at org.apache.struts.action.ActionServlet.init(ActionServlet.java:336)
 at org.seasar.struts.servlet.S2ActionServlet.init(S2ActionServlet.java:61)


のようなエラーが発生しました。

このエラーからはわかりにくいのですが、原因はstruts-config.xmlの記述にありました。

 --- struts-config.xml ------------------------------
 <plug-in className="org.seasar.struts.plugin.AutoStrutsConfigRegisterPlugIn">
   :
 </plug-in>
 <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
   :
 </plug-in>
 ----------------------------------------------------

のように記述していたのですが、StrutsのValidatorプラグインより先に
AutoStrutsConfigRegisterプラグインを定義していた
ため、
AutoStrutsConfigRegisterプラグインからValidatorを参照しようとした際に、
NullPointerExceptionが発生していたようです。

対応は、

 --- struts-config.xml ------------------------------
 <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
   :
 </plug-in>
 <plug-in className="org.seasar.struts.plugin.AutoStrutsConfigRegisterPlugIn">
   :
 </plug-in>
 ----------------------------------------------------

のように、Validatorプラグインを先に書くだけです。

にしてもNullPointerExceptionが出ると原因特定に骨が折れます。

スポンサーサイト

テーマ:JAVA - ジャンル:コンピュータ

  1. 2006/09/28(木) 00:14:39|
  2. ソフトウェア開発 Seasar
  3. | トラックバック:0
  4. | コメント:0

S2Strutsのアノテーションによるバリデーションでエラーメッセージ表示が正しく処理されない

S2StrutsのVALIDATIONアノテーションを使って、
フォームBean(DTO)の入力チェックを行なう場合。。。

 --- HogeDto.java ---------------------------------
 1:public class HogeDto implements Serializable {
 2: private String name;
 3: public static final String name_VALIDATOR_0 = "required";
 4: public static final String name_VALIDATOR_ARGS = "keys=name, resource=true";
 5:
 n: /* 以下略 */
 --------------------------------------------------

な感じに定数アノテーションを書きます。
(JavaSE5.0のアノテーションを使わない場合。詳細はこちらこちら

これでハマりました。

4行目のxxx_VALIDATION_ARGSでは、
 ・keys・・・入力エラーメッセージのプレースホルダを置換する文字列。
       次のresourceがtrueの場合はメッセージリソースのキー名、
       falseの場合は指定した文字列そのものが使用される。
 ・resource・・・メッセージリソースを使用する(true)か、しないか(false)


を指定します。

上記例の場合、
 --- ApplicationResources.properties ----------------
 errors.required = {0}は入力必須です。
 name = 名前
 ----------------------------------------------------
 ※実際は、native2asciiでUnicodeエンコーディングが必要です。

のようなメッセージリソースと組み合わせることで、入力エラー時には
「名前は入力必須です。」と言うメッセージが表示されるはずなのですが、
「nameは入力必須です。」と表示され、nameが名前に変換されません。

あれこれ調べた結果、S2Strutsのドキュメントによると、resourceは省略可能で
省略時はtrueとあるのですが、実際は省略するとfalse扱いになる
ようです。

メッセージの置換文字列をメッセージリソースに定義した場合は、
resource=trueを明示的に書く
必要があります。

テーマ:JAVA - ジャンル:コンピュータ

  1. 2006/09/26(火) 21:02:43|
  2. ソフトウェア開発 Seasar
  3. | トラックバック:0
  4. | コメント:2

iPod対応カーステレオ

iPod対応のカーステレオを買いました。
ALPINEのCDA-9856Jiと言う機種です。

ALPINEは、他のメーカと違ってステレオ自体にiPodとの接続インターフェース
が付いているのが特徴です。
他社製品でiPodに接続するには、大抵別売りの接続機(1~1.5万円もする)が
必要になる
ので、この点でALPINE製品は優れていると思います。

で、実際の使用感ですが。。。イマイチです。
軽視していたのですが、全角文字(漢字など)を表示できないのが致命的でした。
全角文字を含むアーティスト、アルバム、曲名を表示できないので、
聴きたい曲が全角文字を含むと曲を検索できないのです。

あと、ステレオ本体でiPodを操作できるのがウリでしたが、
液晶に表示される情報量も少ない為に操作しにくく、
むしろiPod本体で操作できたほうが良いです。

(ステレオに繋ぐとiPod本体は操作できない)

さらに操作の反応が鈍い
ステレオからiPodのAPI(?)かなにかを呼び出しているせいか、
操作してから反応するまでワンテンポ遅れます。
iPodの軽快な操作感はありません。


と言うわけで。。。
・iPod対応カーステレオを買う場合は、液晶が大きくて表示できる情報量が多い
 カーナビのほうが良い。
 カーナビに手が出ない人は、少なくとも漢字表示対応がオススメ。

・ぶっちゃけ、FMトランスミッタでFM電波で飛ばした方が安上がり
 FMトランスミッタならiPod本体を操作できるので操作もしやすい。


あぁ。。。がっくし。
  1. 2006/09/25(月) 18:52:25|
  2. インプレッション その他
  3. | トラックバック:0
  4. | コメント:0

Strutsの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.NullPointerException
   org.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の
番号を付与する
点だけ要注意です。

テーマ:JAVA - ジャンル:コンピュータ

  1. 2006/09/23(土) 00:25:02|
  2. ソフトウェア開発 Seasar
  3. | トラックバック:0
  4. | コメント:0

Type safe EnumをS2Daoで永続化する

Type safe Enum と S2Dao の組み合わせ方法についてまとめます。

次のようなBeanを永続化します。

--- example.Person.java ---------------------------
public class Person {
 private String name;
 private BloodType bloodType;

 /* アクセサメソッドは省略 */
}
---------------------------------------------------

ここで使われているBloodTypeは、Type safe Enumパターンで実装されています。
(ここではType safe Enumパターンの説明は割愛します。
 詳しくはEffective Javaを参照。
 尚、JavaSE5.0からは言語レベルでサポートされているのでもっと簡単に書けます)

--- example.BloodType.java ------------------------
public final class BloodType {
 public static final BloodType A = new BloodType("A");
 public static final BloodType B = new BloodType("B");
 public static final BloodType AB = new BloodType("AB");
 public static final BloodType O = new BloodType("O");

 private static final Map bloodTypes = new HashMap();
 static {
  bloodTypes.put("A", A);
  bloodTypes.put("B", B);
  bloodTypes.put("AB", AB);
  bloodTypes.put("O", O);
 }

 private final String type;
 private BloodType(String type) {
  this.type = type;
 }

 public static BloodType valueOf(String type) {
  return (BloodType)bloodTypes.get(type);
 }

 public String getType() {
  return type;
 }
}
---------------------------------------------------

このPersonオブジェクトをS2Daoで永続化したい場合、
S2DaoにBloodTypeとデータベースのカラム型の対応を教える必要があります

データベースにBloodType等と言うカラム型はありませんし、
S2DaoもBloodTypeと言う型は認識していません。

これをS2Daoに認識させるには、にorg.seasar.extension.jdbc.ValueTypeを使います。

--- example.BloodTypeValueType.java ---------------
public class BloodTypeValueType implements ValueType {
 public void bindValue(PreparedStatement ps, int i, Object obj)
   throws SQLException {
  ps.setString(i, ((BloodType)obj).getType());
 }
 public Object getValue(ResultSet rs, int i) throws SQLException {
  return BloodType.valueOf(rs.getString(i));
 }
 public Object getValue(ResultSet rs, String s) throws SQLException {
  return BloodType.valueOf(rs.getString(s));
 }
}
----------------------------------------------------

このBloodTypeValueTypeでは、データベースの文字列型(CHAR,VARCHAR等)と
BloodTypeとを対応付けしています。

次に、このBloodTypeValueTypeを使ってPersonオブジェクトと
データベーステーブルの変換を行なうように宣言します。

--- dao.dicon --------------------------------------
 <component
  name="bloodTypeValueType"
  class="example.BloodTypeValueType"/>
----------------------------------------------------

--- example.Person.java ----------------------------
public class Person {
 private String name;
 private static final String bloodType_VALUE_TYPE = "bloodTypeValueType";
 private BloodType bloodType;

 /* アクセサメソッドは省略 */
}
---------------------------------------------------

ダイコンファイルに、作成したBloodTypeValueTypeをコンポーネント登録し、
PersonクラスにアノテーションVALUE_TYPEでそのコンポーネント名を指定します。

最後に、Personを永続化するテーブルです。
--- Person ----------------------------------------
NAME    |VARCHAR2 
BLOODTYPE |VARCHAR2
---------------------------------------------------

以上で、S2Dao内で自動的に BloodTypeとデータベースの文字列型が
相互変換されるようになります。

テーマ:JAVA - ジャンル:コンピュータ

  1. 2006/09/22(金) 00:16:46|
  2. ソフトウェア開発 Seasar
  3. | トラックバック:0
  4. | コメント:0

タグファイルにオブジェクト参照を渡す時に実行時例外発生

JSP2.0のタグファイルで、タグの利用側からタグにオブジェクトを
渡したい場合のトラブル事例。

以下のようなタグファイルを作成したとします。
配置場所は、/WEB-INF/tagsの下です。

--- table.tag -------------------------------------
<%@ attribute name="list" type="java.util.List" required="true"%>
<table>
<% for(Iterator i = list.iterator(); i.hasNext(); ) { %>
<tr>
  <td><%= i.next() %></td>
</tr>
<% } %>
</table>
---------------------------------------------------

このタグにはList型のオブジェクト参照を渡す必要があります。
呼び出し側のJSPは以下です。

--- hoge.jsp --------------------------------------
<%@ taglib tagdir="/WEB-INF/tags" prefix="tag" %>
<tag:table list="${list}"/>
---------------------------------------------------

list="${list}"のようにELを使ってタグにListオブジェクトを渡します

このJSPを呼び出せば、page、request、session、applicationの各スコープから、
"list"と言う名前の属性を探し出し、HTMLの表として表示されるはずです。

が。。。実行してみると、

 org.apache.jasper.JasperException: jsp.error.beans.property.conversion

のような実行時例外が発生します。
タグが要求する型Listと、実際に指定されたオブジェクトの型が一致しないと言うのです。

タグファイルの書き方or呼び出し側のEL式が間違っているのかとさんざん
試行錯誤しましたが、原因はweb.xmlにありました。

web.xmlのServlet APIのバージョンが古く(2.3)、ELが認識されていなかったようで、
web.xmlの<webapp>要素を以下のように記述することで問題が解消しました。(参考

<xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  version="2.4">

テーマ:JAVA - ジャンル:コンピュータ

  1. 2006/09/21(木) 01:27:47|
  2. ソフトウェア開発 Java
  3. | トラックバック:0
  4. | コメント:2

Digesterのデバッグログを抑止する

Struts使用時等、Jakarta Commons Digesterを使ってXMLファイルをロードする場合、
ログ出力設定によっては大量のデバッグログが出力されます。
特にDigesterはログが多くて、アプリの実行速度に支障が出るほどです。

これを抑止するには、Log4Jの設定ファイル(log4j.xml、log4j.properties)で、
rootカテゴリの出力レベルをINFO以上にしてやれば良いのですが、
これだと同じrootカテゴリに出力されている他のログまで影響してしまいます。

Digesterだけログ出力を変更するには、カテゴリorg.apache.commons.digester.Digester
を追加し、その出力レベルをINFO以上にすればOK
です。


--- log4j.xml -------------------------------------
 <category name="org.apache.commons.digester.Digester">
   <priority value="INFO"/>
   <appender-ref ref="xxxx"/>
 </category>

 <root>
   <priority value="DEBUG"/>
   <appender-ref ref="yyyy"/>
 </root>

テーマ:JAVA - ジャンル:コンピュータ

  1. 2006/09/20(水) 00:44:16|
  2. ソフトウェア開発 Java
  3. | トラックバック:0
  4. | コメント:0

Tomcatの配備解除でJarファイルが削除できない

Tomcat Managerの配備解除(undeploy,アンデプロイ)で、/WEB-INF/lib 下の
jarファイルが削除されず、配備解除に失敗する
事があります。

原因はTomcatがjarファイルをロックしている事にあるようで、
削除しようとしても削除できません。

Tomcatを停止すれば削除することができますが、
Tomcat Managerを利用するAntタスクやMavenプラグインが使えなくなるので、
開発作業の効率化を図る上で問題です。

対応としては、Webアプリケーションのコンテキスト定義で、
antiJARLocking属性を指定する
ことで、Jarファイルのロックをしないようにします。

 <Context path="/sample" antiJARLocking="true">
 </Context>

例えば、
${TOMCAT_HOME}/webapp/sample/META-INF/context.xml
のようなコンテキスト定義ファイルを作成し、上記記述を書くと良いと思います。

弊害として、アプリケーションのパフォーマンスが悪化する恐れが
あるようですが、これが致命的なボトルネックになることはないと思います。

テーマ:JAVA - ジャンル:コンピュータ

  1. 2006/09/19(火) 22:25:07|
  2. ソフトウェア開発 Java
  3. | トラックバック:0
  4. | コメント:0

VSSにはドットディレクトリが使えない

Microsoft Visual SourceSafeでの問題。

Javaで開発をしていると、よく「.(ドット)」ではじまるファイルやディレクトリ
が登場します。
UnixやLinuxでは、「.(ドット)」ではじまるファイルやディレクトリは、
隠しファイル/ディレクトリとして扱われるので、Javaの世界でも同じ目的で使われるようです。

具体的には、Eclipseなんかでは.metadataや.settingsのような
ディレクトリに、各種設定や実行ファイルが格納されます。
他にもMavenのリポジトリも.mavenです。

で、こういったドットファイル/ドットディレクトリを、VSSに格納しようとすると。。。

「Visual SourceSafeの構文が不正です。"$/hoge/.moge/" 」

とエラーが出ます。

ドットファイルや、ドットディレクトリそのものはVSSに格納できるのですが、
ドットディレクトリの下にファイルを格納しようとすると上記エラーになります。

Windowsでは、「.(ドット)」で始まるファイルやディレクトリは(基本的に)作成できないので、
VSSもその辺を考慮していないのだと思われます。

よって、Java開発にVSSは使えません。残念。

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2006/09/07(木) 22:53:57|
  2. ソフトウェア開発 一般
  3. | トラックバック:0
  4. | コメント:0

Log4Jをラッパクラスで使用した場合の、ログ出力されるクラス名

Log4J や Commons Logging を利用してログ出力を行なう場合、
org.apache.log4j.Loggerや、org.apache.commons.logging.Log を
そのまま使用するのではなく、ラッパクラスで包んで使用したい
と言う事が良くあります。

MyLog


public class MyLog {

  private final Logger log = Logger.getLog("hoge");

  public void debug(Object message) {
    log.debug(message);
  }
       :
}

この実装で問題なのは、ログに出力されるクラス名です。

例えば、log4j.xmlで。。。

<appender ...>
       :
  <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="%d %-5p [%t] (%F:%L) - %m%n"/>
  </layout>
</appender>

のようなアペンダを設定しておくと、ログには

2006-09-05 20:28:08,072 DEBUG [main] (MyLog.java:12) - メッセージ

のように出力されます。
ログに出力されるクラス名が、"ログを出力したクラス名"ではなく、
"ログのラッパクラス名"が出力されてしまっています。
これでは、どのクラスが出力したログなのかがわかりません。


クラス名を"ログを出力したクラス名"にする為には、
org.apache.log4j.Logger#log(String, Priority, Object, Throwable)を使用します。
このメソッドの第1引数に、ログのラッパクラス名を指定することで、
"ログを出力したクラス名"が出力されるようになります。

public class MyLog {

  private static final String FQCN = "MyLog.java";
  private final Logger log = Logger.getLog("hoge");

  public void debug(Object message) {
    /* ログのラッパクラス名を指定する */
    log.log(FQCN, Level.DEBUG, message, null);

  }
        :
}

この方法には1つ制約があって、Commons Loggingでは実現できません。
Commons LoggingのLogインターフェースには、上記のようなラッパクラス名(FQCN)
を引数に取るメソッドが無いからです。


テーマ:JAVA - ジャンル:コンピュータ

  1. 2006/09/05(火) 20:44:24|
  2. ソフトウェア開発 Java
  3. | トラックバック:0
  4. | コメント:0

Subversionでファイルのロックを強制する

バージョン管理システムSubversionでは、Microsoft Visual SourceSafe
のようなファイルの排他ロックをサポートしています。

が、Subversionの排他ロックはMS-VSSほど積極的なものではなく、
必要に応じてロックすることができる、と言ったものです。

  これは両者の考え方の違いですので、どちらが良い悪いではありません。
  個人的には、ロックは極力使用しないほうが良いと思っているので、
  Subversionのようにロックに消極的なほうが好みです。


プロジェクトの方針によっては、Subversionでも
ファイルのロックをもっと積極的に行ないたいというケースもありますが、
これはSubversionの設定で対応することが可能です。

具体的には、configファイルを修正します。
Windows環境であれば、
C:\Documents and Settings\ユーザ\Application Data\Subversion\config
にあるはずです。

これを2箇所修正します。
1.enable-auto-props = yes がコメントアウトされているので、
コメントを外して有効にする。

2.[auto-props]セクションに、* = svn:needs-lock=true のような
記述を追記する。
*は全てのファイルに対してロックを強制します。
*.javaなどのようにすることで、特定の種類のファイルだけを指定することも可能です。


注意点は、設定が反映されるのは、設定した後にSubversionに追加したファイルだけで、
既にSubversionに格納されているファイルには適用されません


既存のファイルに設定を適用するには、svn propsetコマンドを使う必要があります。

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2006/09/02(土) 13:52:35|
  2. ソフトウェア開発 一般
  3. | トラックバック:0
  4. | コメント:0

プロフィール

Author:crossroad
関西在住。男。
フリーランスのソフトウェアエンジニア。
エレキベース(Rock&Roll)とお酒が好物でございます。

カテゴリー

タグリスト

Java F1 フリーランス ベーシスト HARRY TheStreetSliders iPhone FX お酒 Seasar Maven eclipse Wicket マイホーム 野球 プロジェクトファシリテーション Rails Ruby UML お店 ソフトウェア Tomcat S2Flex2 jsf Teeda Eclipse タグライブラリ ajax タスク europa mylyn trac 

ブログ内検索

最近の記事

最近のコメント

最近のトラックバック

カレンダー

08 | 2006/09 | 10
- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

月別アーカイブ

全ての記事を表示する

全ての記事を表示する

Twitter


RSSフィード

リンク

このブログをリンクに追加する

アクセスカウンタ

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