S2.3RC1の自動登録での怪しい挙動
別のパッケージに同じ名前のクラス名があるときに、org.seasar.framework.container.autoregister.DefaultAutoNamingでコンポーネント名を自動解決すると、バッティングしてコンポーネント登録に失敗するようです。
登録時にエラーにならず、コンポーネント取得時に始めて気がつくという状態。
一応、原因はわかりました。
↓初、続きを読む。
sample.autoregist Greeting GreetingClient GreetingClientImpl GreetingImpl GreetingMain sample.dicon sample.autoregist.sub GreetingClient GreetingClientImpl
というパッケージ構成で、(それぞれ何をやっているかはクラス名からご想像ください(^^;)
<component class="sample.autoregist.GreetingImpl" ></component> <component class="sample.autoregist.sub.GreetingClientImpl" ></component> <component class="sample.autoregist.GreetingClientImpl" ></component>
というdiconファイルを書いて、明示的にコンポーネント登録すると、
public class GreetingMain { private static final String PATH = "sample/autoregist/sample.dicon"; public static void main(String[] args) { S2Container container = S2ContainerFactory.create(PATH); container.init(); System.out.println(container.getComponent(sample.autoregist.GreetingClient.class)); System.out.println(container.getComponent(sample.autoregist.sub.GreetingClient.class)); } }
の結果は、
sample.autoregist.GreetingClientImpl@3eca90 sample.autoregist.sub.GreetingClientImpl@64dc11
と期待通り。
ここで、diconファイルをコンポーネント自動登録用に書き換えてみる。
<component class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister"> <property name="fileNameOfRoot">"app.dicon"</property> <property name="autoNaming"> <component class="org.seasar.framework.container.autoregister.DefaultAutoNaming"/> </property> <initMethod name="addClassPattern"> <arg>"sample.autoregist"</arg> <arg>".*Impl"</arg> </initMethod> <initMethod name="registAll"/> </component>
そうすると…、
sample.autoregist.GreetingClientImpl@d70d7a Exception in thread "main" org.seasar.framework.container.ComponentNotFoundRuntimeException: [ESSR0046]コンポーネント(interface sample.autoregist.sub.GreetingClient)が見つかりません at org.seasar.framework.container.impl.S2ContainerBehavior$DefaultProvider.acquireFromGetComponentDef(S2ContainerBehavior.java:83) at org.seasar.framework.container.impl.S2ContainerBehavior$DefaultProvider.acquireFromGetComponent(S2ContainerBehavior.java:77) at org.seasar.framework.container.impl.S2ContainerBehavior.acquireFromGetComponent(S2ContainerBehavior.java:41) at org.seasar.framework.container.impl.S2ContainerImpl.getComponent(S2ContainerImpl.java:100) at sample.autoregist.GreetingMain.main(GreetingMain.java:18)
と、sample.autoregist.subパッケージの方のGreetingClientImplがコンポーネント登録されていないといわれてしまう!
interaface名のGreetingClientがかぶっているが原因かと思い、subの方のinterafaceだけSubGreetingClientとしても…、
sample.autoregist.GreetingClientImpl@d70d7a Exception in thread "main" org.seasar.framework.container.ComponentNotFoundRuntimeException: [ESSR0046]コンポーネント(interface sample.autoregist.sub.SubGreetingClient)が見つかりません at org.seasar.framework.container.impl.S2ContainerBehavior$DefaultProvider.acquireFromGetComponentDef(S2ContainerBehavior.java:83) at org.seasar.framework.container.impl.S2ContainerBehavior$DefaultProvider.acquireFromGetComponent(S2ContainerBehavior.java:77) at org.seasar.framework.container.impl.S2ContainerBehavior.acquireFromGetComponent(S2ContainerBehavior.java:41) at org.seasar.framework.container.impl.S2ContainerImpl.getComponent(S2ContainerImpl.java:100) at sample.autoregist.GreetingMain.main(GreetingMain.java:18)
となりエラー。
ふむ。見つからないといっているinterface名はSubGreetingClientになってますね。
今度はinterface名は元に戻して、subの方の実装クラス名だけをSubGreetingClientImplにしてみると…、
sample.autoregist.GreetingClientImpl@d70d7a sample.autoregist.sub.SubGreetingClientImpl@b5f53a
んぉ?成功か。
というわけで、実装クラス名が問題のようだ。
コンポーネント名の自動解決辺りが怪しい?
DefaultAutoNamingではクラス名の先頭を小文字にして末尾がImplならそれを除去した文字列をコンポーネント名として返している。
これ自体は別にまあ標準ですよね。
で、普通ならコンポーネント名がバッティングしてはいるけど、正常に登録されるんじゃないかと思います。コンポーネント名greetingClientで取得しようとしたら、TooMany〜Exceptionが出る、っていう例の動きですね。それなら納得できるんです。
ためしに、diconファイルを
<component class="sample.autoregist.GreetingImpl" ></component> <component name="greetingClient" class="sample.autoregist.sub.GreetingClientImpl" ></component> <component name="greetingClient" class="sample.autoregist.GreetingClientImpl" ></component>
としてみましょう。kijimunaが怒りますが、まあそれは無視して実行。
sample.autoregist.GreetingClientImpl@3eca90 sample.autoregist.sub.GreetingClientImpl@64dc11
やっぱり動きますよね。
で、greetingClientというコンポーネント名で取得する行をmainに追加してみると
Exception in thread "main" org.seasar.framework.container.TooManyRegistrationRuntimeException: [ESSR0045]greetingClientに複数のコンポーネント(sample.autoregist.sub.GreetingClientImpl, sample.autoregist.GreetingClientImpl)が登録されています at org.seasar.framework.container.impl.TooManyRegistrationComponentDefImpl.getComponent(TooManyRegistrationComponentDefImpl.java:43) at org.seasar.framework.container.impl.S2ContainerImpl.getComponent(S2ContainerImpl.java:104) at sample.autoregist.GreetingMain.main(GreetingMain.java:19)
ですよねぇ。これなら予想通りなんで納得です。
でも、今回は
Exception in thread "main" org.seasar.framework.container.ComponentNotFoundRuntimeException: [ESSR0046]コンポーネント(interface sample.autoregist.sub.SubGreetingClient)が見つかりません
なんですよねぇ。そもそも登録されていない。
ってことで、FileSystemComponentAutoRegisterのソースを見てみましょう。
protected void regist(ClassPattern classPattern, File packageDir, String packageName) { // 〜(省略)〜 if (classPattern.isApplied(shortClassName)) { String className = packageName == null ? shortClassName : packageName + "." + shortClassName; ComponentDef cd = annoHandler.createComponentDef(className); if (cd.getComponentName() == null && autoNaming != null) { cd.setComponentName(autoNaming.defineName(packageName, shortClassName)); } if (hasComponentDef(cd.getComponentName())) { // ---★ continue; } annoHandler.appendDI(cd); getContainer().register(cd); } } }
ありましたね。★の部分ですね。同じコンポーネント名だったら登録しないと。
これって、明示的指定の場合と振る舞いが違いませんか?
ここのif文3行を削除すると、元の構成で
sample.autoregist.GreetingClientImpl@d70d7a sample.autoregist.sub.GreetingClientImpl@b5f53a
となりました。期待通り。
で、コンポーネント名greetingClientで取得すると、
Exception in thread "main" org.seasar.framework.container.TooManyRegistrationRuntimeException: [ESSR0045]greetingClientに複数のコンポーネント(sample.autoregist.GreetingClientImpl, sample.autoregist.sub.GreetingClientImpl)が登録されています at org.seasar.framework.container.impl.TooManyRegistrationComponentDefImpl.getComponent(TooManyRegistrationComponentDefImpl.java:43) at org.seasar.framework.container.impl.S2ContainerImpl.getComponent(S2ContainerImpl.java:104) at sample.autoregist.GreetingMain.main(GreetingMain.java:19)
ふむ。期待通り。
コンポーネント名がnullならOKなんで、diconファイルでDefaultAutoNamingを指定しなければ、それはそれで正常に通るんですけどね。
[追記]
RC2で修正されました。