SpringでS2Daoを使う -その3-
かなり間が空いてしまいましたが、SpringでS2Daoを使うの3回目です。S2Daoで実装クラス(Employee2DaoImpl)にS2DaoInterceptorをかけた場合のエラーとS2のバージョンを2.4.xにしたものを下記におきました。
http://www.asahi-net.or.jp/~wh6n-icmr/spring-s2dao-example2.zip
変更のポイントは、下記のようにinterceptorのかけ方を変更したのとS2の2.4.xへの対応(JTAがらみ?のインタフェース変更)のために、dao.xmlを変更したことです。
Class targetClass = ClassUtil.forName(className);
Class enhancedClass;
AspectWeaver weaver = new AspectWeaver(targetClass, null);
Method methods = targetClass.getMethods();
for (int i = 0; i < methods.length; ++i) {
Method method = methods[i];
if (isBridgeMethod(method)) {
continue;
}
List interceptorList = new ArrayList();
for (int j = 0; j < interceptorNames.length; j++) {
MethodInterceptor interceptor = (MethodInterceptor) getBeanFactory()
.getBean(interceptorNames[j]);
interceptorList.add(interceptor);
}
if (!isApplicableAspect(method)) {
continue;
}
if (interceptorList.size() == 0) {
weaver.setInterceptors(method, new MethodInterceptor[0]);
} else {
weaver.setInterceptors(method,
(MethodInterceptor) interceptorList
.toArray(new MethodInterceptor[interceptorList.size()]));
}
}
enhancedClass = weaver.generateClass();
制限としては、FileSystemBeanAutoRegister.getRootDirの実装がS2と異なり手抜きをしているため、beanRefContext.xmlが存在することが前提となっています。これは、ちょっといけてないので本当は修正したかったのですが、S2のようにルートパスを取得する方法がわからなかったため、そのままになっています。あとは、各ライブラリが若干古いのですが、ちょっと整理する時間がなかったので、そのままあげています。その他、詳細はダウンロード後readme.txtを確認して下さい。
SpringでS2Daoを使う -その1-
久しぶりの書き込みになってしまいましたが、ボチボチ書き込みして行こうと思います。
最近Springを使う機会があったのですが、S2との違いに戸惑うばかり・・・。設定ファイルを書くのも面倒だし、Dao層にもS2Daoのように簡単に使えるものがないし。というわけで、SpringでBeanの自動登録とS2Daoが利用できないかと思い試してみました。こんなことをやる人はいないと思いますが、参考までにプロジェクト毎下記においておきます。一応、 S2Daoのs2-dao-examplesが基本動作することを確認しています。(一部を除く)
http://www.asahi-net.or.jp/~wh6n-icmr/spring-s2dao-example.zip
http://www.asahi-net.or.jp/~wh6n-icmr/spring-s2dao-example_src.zip (srcのみ)
具体的に作成(修正)したプログラムは、下記となります。
- S2Dao関連
- Bean登録関連
Daoの登録は、beans.xml内の下記の設定で行っています。
<bean class="framework.autoregister.FileSystemBeanAutoRegister"> <property name="addPackageName"> <value>examples.dao</value> </property> <property name="addClassNames"> <value>.*Dao,.*Manager</value> </property> </bean> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <value>*Dao,*Manager</value> </property> <property name="interceptorNames"> <list> <value>s2DaoInterceptor</value> <value>traceInterceptor</value> </list> </property> </bean>
このようにS2同様のイメージでBeanの自動登録が可能です。
【制限事項】
(1)Employee2DaoClientTestが動作しません。(原因不明)
(2)S2DaoTestCaseは利用できません。
(3)S2Dao Tiger/S2Dao Backport175の動作確認はしていません。
Spring初心者だったので、id:koichikさんのSpring Framework 入門記には大変お世話になりました。ありがとうございました。
SpringでS2Daoを使う -その2-
動かないのは、S2Daoで実装クラス(Employee2DaoImpl)にS2DaoInterceptorをかけた場合です。getEmployeesが見つからないとMethodNotFoundRuntimeExceptionが発生してしまっています。AbstractBeanAutoRegister.registerで下記のコードでクラス生成後、Springに登録しているのですがこの辺が駄目なようですが、色々試してみたもののどうしたら良いかわかりませんでした。
Class targetClass = ClassUtil.forName(className); AspectWeaver weaver = new AspectWeaver(targetClass, null); Method[] methods = targetClass.getDeclaredMethods(); for (int i = 0; i < methods.length; ++i) { weaver.setInterceptors(methods[i], new MethodInterceptor[0]); } Class enhancedClass = weaver.generateClass();
あとは、S2のバージョンを2.4.xにしたら(2.3.xではOK)、JTA関連の実装が変わったのかS2のTransactionManagerImplをSpringのJtaTransactionManagerのpropertyに設定するとTypeMismatchExceptionが発生しました。
JSTLのi18nタグ(fmt)を利用したら文字化け(回避方法)
id:n-ichimura:20060302のTomcat4.1(Servlet 2.3)環境でJSTLのi18nタグの
修正対象は、org.apache.taglibs.standard.tag.common.fmt.SetLocaleSupportです。setResponseLocaleメソッドのresponse.setLocale(locale);をコメントアウトすると、文字エンコーディングが暗黙でServletResponseに設定されなくなります。
DWRを使う
下記のURLの内容を参考にDWRを使ってみました。
http://www3.vis.ne.jp/~asaki/p_diary/diary.cgi?Date=2005-11-04
このcreatorを利用したところ、引数で全てのパラメータを渡すのであれば問題なかったのですが、セッションに格納されているログインユーザの情報を利用したかったので、下記のように書き換えました。
S2Creator.java
package sample.dwr; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.seasar.framework.beans.BeanDesc; import org.seasar.framework.beans.PropertyDesc; import org.seasar.framework.beans.factory.BeanDescFactory; import org.seasar.framework.container.ComponentDef; import org.seasar.framework.container.S2Container; import org.seasar.framework.container.factory.SingletonS2ContainerFactory; import org.seasar.struts.util.RequestUtil; import uk.ltd.getahead.dwr.WebContextFactory; import uk.ltd.getahead.dwr.create.AbstractCreator; public class S2Creator extends AbstractCreator { private String beanName; private Class clazz; public void setBeanName(String beanName) { this.beanName = beanName; } public Class getType() { if (clazz == null) { try { S2Container container = SingletonS2ContainerFactory.getContainer(); HttpServletRequest request = WebContextFactory.get().getHttpServletRequest(); container.setRequest(request); ComponentDef def = container.getComponentDef(beanName); clazz = def.getComponentClass(); } catch (Exception ex) { clazz = Object.class; } } return clazz; } public Object getInstance() throws InstantiationException { S2Container container = SingletonS2ContainerFactory.getContainer(); ComponentDef cd = container.getComponentDef(beanName); Object component = cd.getComponent(); BeanDesc beanDesc = BeanDescFactory.getBeanDesc(cd.getComponentClass()); importProperties(component, container, beanDesc); return container.getComponent(beanName); } private void importProperties(Object component, S2Container container, BeanDesc beanDesc) { for (int i = 0; i < beanDesc.getPropertyDescSize(); i++) { PropertyDesc propertyDesc = beanDesc.getPropertyDesc(i); importProperty(component, container, propertyDesc); } } private static Map primitiveMap = new HashMap(); static { primitiveMap.put(Character.TYPE, Character.class); primitiveMap.put(Short.TYPE, Short.class); primitiveMap.put(Integer.TYPE, Integer.class); primitiveMap.put(Long.TYPE, Long.class); primitiveMap.put(Double.TYPE, Double.class); primitiveMap.put(Float.TYPE, Float.class); primitiveMap.put(Boolean.TYPE, Boolean.class); } private Class getPrimitiveWrappedClass(Class primitiveClass) { return (Class) primitiveMap.get(primitiveClass); } private void importProperty(Object action, S2Container container, PropertyDesc propertyDesc) { if (!propertyDesc.hasWriteMethod()) { return; } String propertyName = propertyDesc.getPropertyName(); Object value = getValue(container, propertyName); if (value == null) { return; } Class propertyType = propertyDesc.getPropertyType(); if (propertyType.isPrimitive()) { propertyType = getPrimitiveWrappedClass(propertyType); } if (propertyType.isInstance(value)) { propertyDesc.setValue(action, value); } } private Object getValue(S2Container container, String name) { Object var = RequestUtil.getValue(container.getRequest(), name); if (var != null) { return var; } if (container.hasComponentDef(name)) { return container.getComponent(name); } return null; } }
importPropertiesの部分は、HttpServletRequestとSessionのコンポーネントをDIするために、S2StrutsのBindingUtilを参考に追加しています。
このcreatorをWEB-INF直下のdwr.xmlに登録します。
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 1.0//EN" "http://www.getahead.ltd.uk/dwr/dwr10.dtd"> <dwr> <init> <creator id="s2" class="sample.dwr.S2Creator"/> </init> <allow> <convert converter="bean" match="sample.dto.Sample1Dto"/> <create creator="s2" javascript="Sample1" scope="request"> <param name="beanName" value="sample1Action"/> <include method="findSample1"/> </create> <convert converter="bean" match="sample.dto.Sample2Dto"/> <create creator="s2" javascript="Sample2" scope="request"> <param name="beanName" value="sample2Action"/> <include method="findSample2List"/> </create> </allow> </dwr>
Sample1ActionとSample2Actionは、S2にコンポーネントを登録しておきます。
Sample1Action.java
package sample.action.dwr; import sample.dto.Sample1Dto; public interface Sample1Action { public Sample1Dto findSample1(String cd); }
Sample2Action.java
package sample.action.dwr; import java.util.List; public interface Sample2Action { public List findSample2List(String cd); }
このコンポーネントを呼び出すJSPは、下記のようになります。
sample.jsp
<script type="text/javascript" src="../dwr/engine.js"></script> <script type="text/javascript" src="../dwr/util.js"></script> <script type="text/javascript" src="../dwr/interface/Sample1.js"></script> <script type="text/javascript" src="../dwr/interface/Sample2.js"></script> <script type="text/javascript"> <!-- function updateSample1(cd) { Sample1.findSample1(getSample1, cd); } function getSample1(sample1) { DWRUtil.setValue("cd", sample1.cd); DWRUtil.setValue("name", sample1.name); } function updateSample2(cd) { Sample2.findSample2List(getSample2List, cd); } function getSample2List(sample2List) { DWRUtil.removeAllOptions("sample2"); DWRUtil.addOptions("sample2", sample2List, "cd", "name"); } //--> </script> <input type="text" name="cd" value=""> <input type="text" name="name" value=""> <input type="button" onclick="updateSample1();"> <select name="sample2" id="sample2" onchange="updateSample2(this.value);"> <option value="01">テスト01</option> <option value="02">テスト02</option> <option value="03">テスト03</option> <option value="04">テスト04</option> </select>
S2PagerとBLOB
S2Pagerを使っているのですが、ファイルアップロードされたファイルをS2DaoでOracleのBLOB型に格納しようとしたところ、下記のエラーが発生しました。
エラー内容
org.seasar.framework.exception.SQLRuntimeException:[ESSR0071]SQLで例外が発生しました。 理由はjava.sql.SQLException: ストリームをScrollableResultSetまたはUpdatableResultSetにバインドできません at org.seasar.extension.jdbc.impl.BasicHandler.bindArgs(BasicHandler.java:110) at org.seasar.dao.impl.AbstractAutoHandler.execute(AbstractAutoHandler.java:142) at org.seasar.dao.impl.AbstractAutoHandler.execute(AbstractAutoHandler.java:122) at org.seasar.dao.impl.AbstractAutoStaticCommand.execute(AbstractAutoStaticCommand.java:49) at org.seasar.dao.interceptors.S2DaoInterceptor.invoke(S2DaoInterceptor.java:51) at org.seasar.dao.pager.PagerS2DaoInterceptorWrapper.invoke(PagerS2DaoInterceptorWrapper.java:63) at org.seasar.framework.aop.impl.NestedMethodInvocation.proceed(NestedMethodInvocation.java:41) at org.seasar.framework.aop.interceptors.TraceInterceptor.invoke(TraceInterceptor.java:50) at org.seasar.framework.aop.impl.NestedMethodInvocation.proceed(NestedMethodInvocation.java:41) at org.seasar.framework.aop.interceptors.InterceptorChain.invoke(InterceptorChain.java:41)
ScrollableResultSetを利用した場合、byte配列からBLOGからのINSERTでエラーになるようです。とりあえず、エラーを回避するため、dao.diconの設定を
↓
BLOB型が含まれる時のみ、スクロールカーソルを利用するようにはできないものか調べてみましたがわからず・・・。時間ができたら調べてみよう。