[Seasar-user:21185] HotDeployモードでMethodクラスからアノテーションが取得できない
Shouta Morimoto
[E-MAIL ADDRESS DELETED]
2011年 12月 6日 (火) 15:51:02 JST
森本と申します。
件名の件について質問させて頂きます。
Webアプリケーションの認証処理をRequestProcessorを拡張することで
実現しようとしています。
(「Seasar 2 徹底入門」の6.4.4章を参照しています。)
具体的には認証が必要なメソッドに@Authアノテーションを付与し、
RequestProcessorで要求されたメソッドに@Authアノテーションが
付与されているかをチェックする。付与されていた場合は認証
画面へフォワードするという処理を実装しました。
本方式で実装したところ、CoolDeployモードでは想定通りの動作をします。
しかしHotDeployモードでは、tomcat起動後の1回目のリクエストでは
想定通りの動作をするのですが、2回目以降の動作ではRequestProcessor
の処理で@Authアノテーションを拾えなくなってしまいます。
具体的なコードと設定を下記に示させて頂きます。
■====================ここから====================■
■<rootパッケージ名>.action.test.AuthTestAction
⇒ユーザ認証を必要とするメソッドを持つアクションクラス
------------------------------------------------------------
package <rootパッケージ名>.action.test;
import javax.annotation.Resource;
import org.seasar.struts.annotation.Execute;
import <rootパッケージ名>.annotation.Auth;
import <rootパッケージ名>.dto.UserDto;
public class AuthTestAction {
@Resource
protected UserDto userDto;
@Execute(validator = false)
@Auth
public String index() {
if (userDto.user == null) {
System.out.println("userDto.user is null!!");
} else {
System.out.println("userDto.user is not null, id = " +
userDto.user.id);
}
return null;
}
}
------------------------------------------------------------
■<rootパッケージ名>.annotation
------------------------------------------------------------
package <rootパッケージ名>.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Auth {
}
------------------------------------------------------------
■<rootパッケージ名>.dto.UserDto
⇒認証済みユーザ情報を格納しておくクラス
------------------------------------------------------------
package <rootパッケージ名>.dto;
import java.io.Serializable;
import org.seasar.framework.container.annotation.tiger.Component;
import org.seasar.framework.container.annotation.tiger.InstanceType;
import <rootパッケージ名>.entity.User;
@Component(instance = InstanceType.SESSION)
public class UserDto implements Serializable {
private static final long serialVersionUID = 1L;
public User user = null;
public boolean isLogin() {
if (user != null) {
return true;
}
return false;
}
}
------------------------------------------------------------
■<rootパッケージ名>.SUGRequestProcessor
⇒S2RequestProcessorを拡張した独自クラス
------------------------------------------------------------
package <rootパッケージ名>;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.InvalidCancelException;
import org.seasar.framework.container.SingletonS2Container;
import org.seasar.struts.action.S2RequestProcessor;
import org.seasar.struts.config.S2ExecuteConfig;
import org.seasar.struts.util.S2ExecuteConfigUtil;
import org.seasar.struts.util.URLEncoderUtil;
import <rootパッケージ名>.annotation.Auth;
import <rootパッケージ名>.dto.UserDto;
import <rootパッケージ名>.exception.AuthException;
import <rootパッケージ名>.util.SUGConf;
public class SUGRequestProcessor extends S2RequestProcessor {
@Override
public void process(HttpServletRequest request, HttpServletResponse
response)
throws IOException, ServletException {
request = processMultipart(request);
String path = processPath(request, response);
if (path == null) {
return;
}
processLocale(request, response);
processContent(request, response);
processNoCache(request, response);
if (!processPreprocess(request, response)) {
return;
}
processCachedMessages(request, response);
ActionMapping mapping = processMapping(request, response, path);
if (mapping == null) {
return;
}
ActionForm form = processActionForm(request, response, mapping);
processPopulate(request, response, form, mapping);
try {
if (!processRoles(request, response, mapping)) {
return;
}
} catch (AuthException ae) {
// ログインページにリダイレクトする前にリクエストされたURLをクエリ
ストリングに保持
String requestedURL = (String) request
.getAttribute("javax.servlet.forward.servlet_path");
if (request.getAttribute("javax.servlet.forward.query_string") !=
null) {
requestedURL += "?"
+ (String) request
.getAttribute("javax.servlet.forward.query_string");
}
String redirectURL = SUGConf.loginURL + "?" + SUGConf.requestedURLStr
+ "=" + URLEncoderUtil.encode(requestedURL);
// ログインページにリダイレクトさせる
ActionForward forward = new ActionForward(redirectURL, true);
processForwardConfig(request, response, forward);
return;
}
try {
if (!processValidate(request, response, form, mapping)) {
return;
}
} catch (InvalidCancelException e) {
ActionForward forward = processException(request, response, e, form,
mapping);
processForwardConfig(request, response, forward);
return;
} catch (IOException e) {
throw e;
} catch (ServletException e) {
throw e;
}
if (!processForward(request, response, mapping)) {
return;
}
if (!processInclude(request, response, mapping)) {
return;
}
Action action = processActionCreate(request, response, mapping);
if (action == null) {
return;
}
ActionForward forward = processActionPerform(request, response, action,
form, mapping);
processForwardConfig(request, response, forward);
}
@Override
protected boolean processRoles(HttpServletRequest request,
HttpServletResponse response, ActionMapping mapping) throws
IOException,
ServletException {
S2ExecuteConfig executeConfig = S2ExecuteConfigUtil.getExecuteConfig();
Auth auth = executeConfig.getMethod().getAnnotation(Auth.class);
if (auth != null) {
UserDto userDto = SingletonS2Container.getComponent(UserDto.class);
boolean isLogin = userDto.isLogin();
if (!isLogin) {
// 認証例外を発生させ、ログインページにリダイレクトさせる
throw new AuthException();
}
}
return super.processRoles(request, response, mapping);
}
}
------------------------------------------------------------
■convention.dicon
------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
<component
class="org.seasar.framework.convention.impl.NamingConventionImpl">
<initMethod name="addRootPackageName">
<arg>"<rootパッケージ名>"</arg>
</initMethod>
<initMethod name="addIgnorePackageName">
<arg>"<rootパッケージ名>.dto"</arg>
</initMethod>
<initMethod name="addIgnorePackageName">
<arg>"<rootパッケージ名>.annotation"</arg>
</initMethod>
</component>
<component
class="org.seasar.framework.convention.impl.PersistenceConventionImpl"/>
</components>
------------------------------------------------------------
■app.dicon
------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components>
<include path="convention.dicon"/>
<include path="aop.dicon"/>
<include path="j2ee.dicon"/>
<include path="s2jdbc.dicon"/>
<component name="actionMessagesThrowsInterceptor"
class="org.seasar.struts.interceptor.ActionMessagesThrowsInterceptor"/>
<!-- 自作コンポーネントの登録 -->
<component name="userDto" class="<rootパッケージ名>.dto.UserDto"
instance="session"/>
</components>
------------------------------------------------------------
■====================ここまで====================■
デバッグモードで確認してみると、HotDeployモード時のtomcat起動後2回目
以降のアクセスだと、SUGRequestProcessorクラスの以下の行にて、
getAnnotationメソッドの返り値がnullとなってしまうようです。
Auth auth = executeConfig.getMethod().getAnnotation(Auth.class);
もう少し詳しく見てみると、java.lang.reflect.Methodクラスにて、
Map型のdeclaredAnnotations変数からAuth.classを引数にして
getメソッドを呼んだ際に、declaredAnnotations変数にはAuthアノテーション
が入っているにも関わらず、引数のAuthクラスとはhash値が異なるため
mapからの取得ができていないようです。
以上、恐れ入りますが原因がお分かりの方がいらっしゃれば
お教え頂ければ幸いです。
■開発環境
OS:Windows 7 Home Premium (64bit)
ブラウザ: Firefox 8.0
DB: mysql5.5
コンパイラ: jdk1.6.0_22
使用中のライブラリ:(Jarを一部抜粋)
- sa-struts-1.0.4-sp8.jar
- struts-1.2.9.jar
- mysql-connector-java-5.1.14-bin.jar
- s2-framework-2.4.41.jar
- s2-tiger-2.4.41.jar
- s2-extension-2.4.41.jar
- s2jdbc-gen-2.4.41.jar
Seasar-user メーリングリストの案内