Javaリフレクションを使ってみた

リフレクションって慣れないけれど面白い。
いくつかメモメモ。
こんな感じでクラスを作り、リフレクションで情報を取得してみました。


【作ったクラス】

                                                                                      • -

    
static class ADto implements BaseDto{
private static String q ="hoge";
public String s=null;
public int i=10;
BDto b=new BDto();
final String qa ="hogehoge";
}

static class BDto implements BaseDto{
public static String q ="hogeb";
public String s=" bb ";
public int i=20;
}



【調べたメソッド】

                                                                                      • -


for(Field f : returnObject.getClass().getDeclaredFields()){
System.out.println(f.toString());
System.out.println(f.getDeclaringClass());
System.out.println(f.getType());
System.out.println(f.getClass());
}


【結果】

                                                                                      • -

hoge
private static java.lang.String kkk.comon.interceptor.SqlCheckInterceptor$ADto.q
class kkk.comon.interceptor.SqlCheckInterceptor$ADto
class java.lang.String
class java.lang.reflect.Field


10
public int kkk.comon.interceptor.SqlCheckInterceptor$ADto.i
class kkk.comon.interceptor.SqlCheckInterceptor$ADto
int
class java.lang.reflect.Field


kkk.comon.interceptor.SqlCheckInterceptor$BDto@e09713
kkk.comon.interceptor.SqlCheckInterceptor$BDto kkk.comon.interceptor.SqlCheckInterceptor$ADto.b
class kkk.comon.interceptor.SqlCheckInterceptor$ADto
class kkk.comon.interceptor.SqlCheckInterceptor$BDto
class java.lang.reflect.Field


hogeb
public static java.lang.String kkk.comon.interceptor.SqlCheckInterceptor$BDto.q
class kkk.comon.interceptor.SqlCheckInterceptor$BDto
class java.lang.String
class java.lang.reflect.Field


bb
public java.lang.String kkk.comon.interceptor.SqlCheckInterceptor$BDto.s
class kkk.comon.interceptor.SqlCheckInterceptor$BDto
class java.lang.String
class java.lang.reflect.Field


20
public int kkk.comon.interceptor.SqlCheckInterceptor$BDto.i
class kkk.comon.interceptor.SqlCheckInterceptor$BDto
int
class java.lang.reflect.Field


hogehoge
final java.lang.String kkk.comon.interceptor.SqlCheckInterceptor$ADto.qa
class kkk.comon.interceptor.SqlCheckInterceptor$ADto
class java.lang.String
class java.lang.reflect.Field

S2StrutsでFormをSessionに格納する

Sessionへの格納は、
@ExportToSessionを書くと実行できます。

                                                                                      • -

ですがFormはこうかいても、Sessionに格納とはなりません。


下記S2Strutsリファレンスを元に、Actionクラスのアノテーション
@StrutsActionの書き方を変えないといけません。
デフォルトではリクエストで生成されるようです。


@StrutsAction(name="HogeForm",scope=ScopeType.SESSION)
public interface HogeAction extends Root{



↓こんな感じ




【参考URL】
http://s2struts.seasar.org/ja/1.2/s2struts.html#ZeroConfigReference

Seasarで、独自Interceptorを複数使用する

ログインチェックを行うInterceptorと、
実行Actionクラス名を開始と終了のタイミングで出力するTraceInterceptorを作成。

TraceInterceptorは、プロパティファイルから該当する名前を取ってこれるようにしました。



【TraceInterceptor】--------------------------------------------

public class TraceInterceptor extends AbstractInterceptor {

private static final long serialVersionUID = 1L;

public Object invoke(MethodInvocation methodinvocation) throws Throwable {

// logicNameプロパティファイルを取得
MessageResources mr = MessageResources
.getMessageResources("hoge.comon.file.logicName");

//実行ActionImplクラス名を取得
String className = getTargetClass(methodinvocation).getSimpleName();

//logicName.propertiesファイルから該当する処理名を取得
String logicName = mr.getMessage(className);

//Action開始をログ出力
System.out.println("----" + logicName + "(" + className
+ ") を開始しました----");

//対象メソッドを実行
Object returnObject = methodinvocation.proceed();

//Action終了をログ出力
System.out.println("----" + logicName + "(" + className
+ ") を終了しました----");

return returnObject;
}

}



【diconファイル】--------------------------------------------
AspectAutoRegisterへの登録は、別々に書きます。


  
<!-- LoginInterceperを適用 -->
<component name="loginInterceptor" class="hoge.comon.interceptor.LoginInterceptor"/>
<!-- TraceInterceptorを適用 -->
<component name="traceInterceptor" class="hoge.comon.interceptor.TraceInterceptor"/>

<component class="org.seasar.framework.container.autoregister.AspectAutoRegister">
<property name="interceptor">traceInterceptor</property>
<initMethod name="addClassPattern">
<arg>"hoge"</arg>
<arg>".*ActionImpl"</arg>
</initMethod>
</component>

<component class="org.seasar.framework.container.autoregister.AspectAutoRegister">
<property name="interceptor">loginInterceptor</property>
<initMethod name="addClassPattern">
<arg>"hoge"</arg>
<arg>".*ActionImpl"</arg>
</initMethod>
<initMethod name="addIgnoreClassPattern">
<arg>"hoge"</arg>
<arg>"TopActionImpl"</arg>
</initMethod>
</component>

                                                                                      • -

Topページは、ログインチェックから除外しています。

Seasarでトランザクション制御

S2daoでは、どのタイミングでロールバックするのか調べてみました。

                                                                                      • -

ActionImpl内で、下記2つのSQLを続けて実行します。



2つ目でエラーが出る仕様ですが、
エラーが出た後も1つ目のUPDATEがロールバックされることはありません。
これでは困ってしまいます。。


1Action1トランザクションにするためにはどうすればいいか。。
下記URLを参考に学習。

今回は、実行メソッドが
「innerProc」であること、
AspectAutoRegisterを利用していることから、diconファイルは以下のようになります。

                                                                                      • -

  
<component class="org.seasar.framework.container.autoregister.AspectAutoRegister">
<property name="interceptor">j2ee.requiredTx</property>
<property name="pointcut">"innerProc"</property>
<initMethod name="addClassPattern">
<arg>"hoge"</arg>
<arg>".*ActionImpl"</arg>
</initMethod>
</component>

                                                                                      • -

これで見事、1Action1トランザクションが実行できました!

★ログの感じ

DEBUG 2010-04-15 16:23:29,328 [http-8080-2] トランザクションを開始しました
DEBUG 2010-04-15 16:23:29,343 [http-8080-2] 論理的なコネクションを取得しました
DEBUG 2010-04-15 16:23:29,343 [http-8080-2] UPDATE TABLE1 SET name = 'yhohoa', dep_code = 100, address_code = '11200001' WHERE name_id = 1
DEBUG 2010-04-15 16:23:29,343 [http-8080-2] 論理的なコネクションを閉じました
DEBUG 2010-04-15 16:23:29,359 [http-8080-2] 論理的なコネクションを取得しました
DEBUG 2010-04-15 16:23:29,359 [http-8080-2] UPDATE TABLE1 SET name = null, dep_code = 100, address_code = '11200001' WHERE name_id = 1
DEBUG 2010-04-15 16:23:29,390 [http-8080-2] 論理的なコネクションを閉じました
DEBUG 2010-04-15 16:23:29,421 [http-8080-2] トランザクションロールバックしました
2010-04-15 16:23:29,421 [http-8080-2] ERROR org.apache.struts.action.RequestProcessor - Execute action
org.seasar.framework.exception.SQLRuntimeException: [ESSR0071]SQLで例外・・・(以下省略)




【参考URL】
http://ml.seasar.org/archives/seasar-user/2006-March/003405.html

s2daoで、外部テーブルから値を取ってこれない!

一日くらい嵌っていました。

【現象】
FKで結合している別表から値が帰ってこない
(直にコマンドプロンプトSQLを投げると実行できるが、
   S2daoで実行すると別表のDTOがNULLで返ってくる)


【状態】
テーブル1はこんな感じ


テーブル2はこんな感じ

DEP_CODEで紐付けています。



【解決】
SELECT TABLE1.*, TABLE2.dep_name AS dep_name_0 ・・・・
と、dep_name に別名をつけなきゃダメ!
※よく見たら、s2daoリファレンス『SQL文を記述する場合のExample』にも
 別名がきちんと記入されていました。

seasar2.4.41 とS2-struts1.2.12 を一緒に使う時の注意点

S2-struts1.2.12のブランクプロジェクトをDLして、そこにS2.4.41
を入れると色々問題がありました

【1】
S2-struts1.2.12は2.3系
 ⇒2.4系に変更すると色々エラーでる

(Ⅰ)Servletは2.3⇒2.4に上げる必要があります
(Ⅱ)javassist-3.0.jar⇒javassist-3.4.ga



【2】geronimo-jta_1.1_spec-1.0.jar をいれる



【3】
jdbc.dicon を作る


j2ee.diconを自力で作らない。JAR内にあるものを利用します。
※2.4系から、j2ee.diconを3分割したそうです。

【参考URL】http://ml.seasar.org/archives/seasar-user/2007-December/012085.html



【4】DB2を使用する場合のjdbc.diconの内容

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
"http://www.seasar.org/dtd/components.dtd">
<components namespace="jdbc">
<include path="jta.dicon"/>

<component class="org.seasar.extension.jdbc.impl.BasicResultSetFactory"/>
<component class="org.seasar.extension.jdbc.impl.BasicStatementFactory"/>

<component name="xaDataSource"
class="org.seasar.extension.dbcp.impl.XADataSourceImpl">
<property name="driverClassName">
"com.ibm.db2.jcc.DB2Driver"
</property>
<property name="URL">
"jdbc:db2://localhost:50000/SAMPLE"
</property>
<property name="user">"db2admin"</property>
<property name="password">"zaq12wsx"</property>
<initMethod name="addProperty">
<arg>"currentSchema"</arg>
<arg>"AA000000"</arg>
</initMethod>
</component>

<component name="connectionPool"
class="org.seasar.extension.dbcp.impl.ConnectionPoolImpl">
<property name="timeout">600</property>
<property name="maxPoolSize">10</property>
<!-- JTAトランザクションが開始されていない場合にコネクションを
取得できないようにするには次のプロパティをfalseにしてください.-->
<property name="allowLocalTx">true</property>
<destroyMethod name="close"/>
</component>
<component name="dataSource"
class="org.seasar.extension.dbcp.impl.DataSourceImpl"/>

</components>