はじめまして,小林 (koichik) と申します. Axis 1.4 で,TypeMappingImpl の doAutoTypes を true に 設定した場合に Map が適切にエンコードされないという現象に 遭遇しています. 以下,長文になりますが状況を詳しく説明します.
TypaMapping は TypeMappingDelegate を使ってチェーン状に 構成することができますが,仮に二つの TypeMappingDlegate が 以下のようにあるとして, next TypeMappingDelegate(1) -----> TypeMappingDelegate(2) └TypeMappingImpl(1) └TypeMappingImpl(2) TypeMappingImpl(1) はほとんど空ですが,Map を扱うために MapSerializer/MapDeserializer を登録しています. TypeMappingImpl(2) には標準のマッピングが登録されています. # この TypeMapping チェーンは WSDDService#initTMR() で # 作成されるものです. そして,TypeMappingImpl(1) の doAutoTypes をtrue に 設定して利用しています. このような構成で戻り値型が Map のメソッドを Java:RPC で 呼び出すと,Map のキーや値 (String) が xsd:base64Binary で エンコードされてしまいます. Axis の動きを追いかけてみたところ,まずは TypeMappingImpl(1) に 登録された MapSerializer がキーや値をシリアライズするために SerializationContext#serialize() を呼び出します. MapSerializer.java(96) ================================================================================ context.serialize(QNAME_KEY, null, key, null, null, Boolean.TRUE); context.serialize(QNAME_VALUE, null, val, null, null, Boolean.TRUE); ================================================================================ ここではシリアライズ対象のオブジェクト (実際は String) である key と val を渡していますが,第 4 引数の xmlType (QName) には null を渡しています. 呼び出された SerializationContext はいくつかのメソッドを経て TypeMappingDelegate(1) の getSerializer() を呼び出します. TypeMappingDelegate(1) はそのまま TypeMappingImpl(1) に委譲します. この時点でも xmlType は null のままです. TypeMappingImpl.java(286〜294) ================================================================================ public javax.xml.rpc.encoding.SerializerFactory getSerializer(Class javaType, QName xmlType) throws JAXRPCException { javax.xml.rpc.encoding.SerializerFactory sf = null; // If the xmlType was not provided, get one if (xmlType == null) { xmlType = getTypeQName(javaType, null); ================================================================================ xmlType が null で呼び出されるため,getTypeQName() を呼び出します. この時の第 2 引数 TypeMappingDelegate は null です. getTypeQName() は XML 型を解決しようとしますが,TypeMappingImpl(1) は String に対するマッピングを持っていません. TypeMappingImpl(2) は String のマッピングを持っていますが, getTypeQName() の第 2 引数で渡された next が null であるため, チェーンの後続から解決することもできません. そして TypeMappingImpl(1) は doAutoTypes が true に設定されて いるため,String に対して BeanSerializer/BeanDesrializer を 登録してしまいます. TypeMappingImpl.java(674〜689) ================================================================================ if (xmlType == null && shouldDoAutoTypes()) { xmlType = new QName( Namespaces.makeNamespace( javaType.getName() ), Types.getLocalNameFromFullName( javaType.getName() ) ); /* If doAutoTypes is set, register a new type mapping for the * java class with the above QName. This way, when getSerializer() * and getDeserializer() are called, this QName is returned and * these methods do not need to worry about creating a serializer. */ internalRegister( javaType, xmlType, new BeanSerializerFactory(javaType, xmlType), new BeanDeserializerFactory(javaType, xmlType) ); } ================================================================================ この結果,String であるマップのキーや値が BeanSerializer により xsd:base64Binary でエンコードされてしまうようです. ここまで調査したのですが,問題が Axis の実装にあるのか, 上で説明した使い方にあるのかが分かりません. TypeMappingDelegate(1) ではなく TypeMappingDelegate(2) の doAutoTypes を true にすべきなのかと思い試してみましたが, その場合 Map は適切に扱えるようになったものの,今度は Bean の配列に対して TypeMappingImpl(1) が Object 配列の Serializer を返してしまうなど,doAutoTypes による BeanSerializer/BeanDeserializer の自動登録が適切に働かなく なってしまいました. ここで (ようやく) 質問なのですが,doAutoTypes を有効にした上で, Map など個別に登録した Serializr/Deserializer も適切に扱うには どのようにすべきなのでしょうか? 正しいやり方が分からないので,現在はとりあえず次のように 回避しています. xmlType が null のまま TypeMappingDelegate(1) が呼ばれると TypeMappingImpl(2) に登録されているマッピングが使われないので, TypeMappingDelegage(1) の前に TypeMappingDelegate サブクラスを TypeMappingDelegate(0) として登録しました. TypeMappingDelegate サブクラスでは getSerializer() をオーバーライドし, TypeMappingImpl に委譲する前に xmlType を解決します. ================================================================================ public SerializerFactory getSerializer(Class javaType, QName xmlType) throws JAXRPCException { if (xmlType == null) { xmlType = getTypeQName(javaType); } return super.getSerializer(javaType, xmlType); ================================================================================ これにより,TypeMappingImpl(2) に登録されている型が 適切にシリアライズされるようになりました. doAutoTypes による BeanSerializer/BeanDeserializer の 自動登録も問題ありません. ただし,TypeMappingDelegate のコンストラクタは可視性が 指定されていないため (package スコープ),やむを得ず 勝手に org.apache.axis.encoding パッケージを使っています. もし TypeMappingDelegate のサブクラスを作成するやり方が 適切なのであれば,コンストラクタを public にして頂けると ありがたいです. 以上,かなりの長文になってしまいましたが,doAutoTypes を有効にして Map も扱うための適切な方法があればご教示頂けないでしょうか. よろしくお願いします. -- <component name="koichik"> <property name="fullName">"Koichi Kobayashi"</property> <property name="email">"[EMAIL PROTECTED]"</property> <property name="blog">"http://d.hatena.ne.jp/koichik"</property> </component> --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]