struts2とseasar2を使ってアプリ作成(準備その4)~警告WSSR0008続編

新しいActionSupportの作成

準備その3
で、の対応として「ActionSupportを使わない」として、こういう風に書きましたが

とはいっても、ActionSupportは何かと便利でもあるのでsetContainerの形を変えて作り直すのもいいと思います。

なかなか作り直すのも面倒だなと思いまして、もう一度見てみました。

http://www.seasar.org/wiki/index.php?WSSR0008

対応指針:
@Binding(bindingType=BindingType.NONE)

つまりActionSupportをオーバーライドしてsetContainerメソッドにアノテーションをつければよいということです。
実際やってみました。

package kamegu.common;

import org.seasar.framework.container.annotation.tiger.Binding;
import org.seasar.framework.container.annotation.tiger.BindingType;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;

public class MyActionSupport extends ActionSupport {

    @Binding(bindingType=BindingType.NONE)
    @Inject
    @Override
    public void setContainer(Container container) {
        super.setContainer(container);
    }
}

クラス名は何でもいいです。
このクラスをプロジェクトで使う基本のアクションクラスにすればいいと思います。
ただし、このクラスを継承したアクションを呼ぶとsetContainerが2回呼ばれるようです(seasarからではなくてstrutsから)。
たぶん、このクラスにもActionSupportにも@Injectアノテーションが定義されているために2回呼ばれるんだと思います(実装未確認)。
なので、@Injectアノテーションを取り除いてやれば1度だけ呼ばれるようになりました。

もしくはこのようにしてもいいようです。

package kamegu.common;

import com.opensymphony.xwork2.ActionSupport;

public class MyActionSupport extends ActionSupport {
	public static final String container_BINDING = "bindingType=none";
}

http://s2container.seasar.org/2.4/ja/DIContainer.html#BindingAnnotation
こっちのほうがシンプルでいいかも。

未定義のPATHにアクセスするとエラーが出る(ESSR0045)

上で作成したクラスを継承してアクションを複数作成した際に、未定義のアクションを予防とするとエラーとなります。
※ このブログで設定してきたとおりになっている場合

致命的: Exception occurred during processing request: Unable to instantiate Action, com.opensymphony.xwork2.ActionSupport,  defined for 'jsp-crudaa' in namespace '/fwtest'[ESSR0045]class com.opensymphony.xwork2.ActionSupportに複数のコンポーネント(kamegu.action.fwtest.JspCrudAction, kamegu.action.fwtest.JspTopAction, kamegu.action.SeasarTestAction, kamegu.action.TopAction)が登録されています
Unable to instantiate Action, com.opensymphony.xwork2.ActionSupport,  defined for 'jsp-crudaa' in namespace '/fwtest'[ESSR0045]class com.opensymphony.xwork2.ActionSupportに複数のコンポーネント(~~Action, ~~Action, ~~Action, ~~Action)が登録されています
	at com.opensymphony.xwork2.DefaultActionInvocation.createAction(DefaultActionInvocation.java:316)
	at com.opensymphony.xwork2.DefaultActionInvocation.init(DefaultActionInvocation.java:397)
	at com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:194)
	at org.apache.struts2.impl.StrutsActionProxy.prepare(StrutsActionProxy.java:63)
~~略~~
Caused by: org.seasar.framework.container.TooManyRegistrationRuntimeException: [ESSR0045]class com.opensymphony.xwork2.ActionSupportに複数のコンポーネント(kamegu.action.fwtest.JspCrudAction, kamegu.action.fwtest.JspTopAction, kamegu.action.SeasarTestAction, kamegu.action.TopAction)が登録されています
	at org.seasar.framework.container.impl.TooManyRegistrationComponentDefImpl.getComponent(TooManyRegistrationComponentDefImpl.java:52)
	at org.seasar.framework.container.impl.S2ContainerImpl.getComponent(S2ContainerImpl.java:129)
	at org.seasar.xwork2.S2ObjectFactory.buildBean(S2ObjectFactory.java:49)
~~略~~

これは、以下の理由で起こっていると思われます。

  • 対象のアクションがなかったときにstruts2準備2で設定したワイルドカードの設定が呼ばれ、その際にデフォルトのアクションが呼ばれる。
  • このデフォルトのアクションクラスはActionSupport。
  • アクションをコンポーネントとして登録する際に、すべての親クラス(Objectクラスを除く)と実装インターフェースがキーとして登録されている
  • これを逆に言うと、ActionSupportにDIする対象としてActionSupportを継承するクラスがすべて登録されている状態。

コンポーネントの自動登録を変更しようとした場合、どうやら設定はできなさそうなのでコード修正する必要があるがそれも面倒。
他の対処方法としては次の2つが思いつきます。

ワイルドカードの設定をやめた場合、UnknownHandlerで対応するとか、エラーを検知して他の画面を表示させるとかいろいろ方法はあると思いますが、
今回はデフォルトのアクションクラスを変える方法をとります。

設定

kamegu.common.NotFoundAction
package kamegu.common;

import com.opensymphony.xwork2.Action;

public class NotFoundAction implements Action {
	@Override
	public String execute() throws Exception {
		return SUCCESS;
	}
}

追加

struts.xml
  <package name="default" extends="struts-default">
    <default-class-ref class="kamegu.common.NotFoundAction" />
    <action name="*">
      <result>/nopage.jsp</result>
    </action>
  </package>

default-class-refを1行追加しているだけです。

以上