カスタムシリアライザとカスタムデシリアライザの作成(AXIS 1.2)
シリアライザとデシリアライザは,自作することもできるらしいので,試しに作ってみた.
シリアライズ,デシリアライズ処理は,大抵の場合はBeanSerializerとBeanDeserializerで事足りると思う.
またAXISでは,他にBase64Serializer,Base64DeserializerやHexSerializer,HexDeserializerなどのシリアライザ,デシリアライザもあり,これらもBean...と同様の手順で使用可能である.
こうした状況なので,稀なケースかもしれないが,場合によっては独自のシリアライズ,デシリアライズを行うカスタムシリアライザとカスタムデシリアライザを作成することもできる.
カスタムシリアライザとカスタムデシリアライザを使用するための作業には以下がある.
- カスタムシリアライザの作成
- カスタムデシリアライザの作成
- カスタムシリアライザファクトリの作成
- カスタムデシリアライザファクトリの作成
- クライアントの作成
- デプロイ
以下にシリアライズ,デシリアライズする対象となるクラスHogeのコードを示す.
Beanなので,BeanSerializer,Deserializerでも処理できるのだが,今回は要件として,HogeのメンバsecretValueの値はそのままの形では送受信してはならないというものを想定した.
そこで,secretValueは,シリアライズの際には暗号化し,デシリアライズの際には復号するよう(※),カスタムシリアライザとデシリアライザを作成する.
※ 暗号化,復号はここでの本題ではないので,文字列を単に逆順にするだけ.
以下にサンプルのカスタムシリアライザ,HogeSerializerを示す.
上記は,BeanSerializerのソースやAXISのJavaDocを参照して,私なりに試行錯誤しつつ作成した.
ポイントはどうやら以下のようだ.
汎用性あるいは拡張性を考慮した設計らしいが,対象を限定するなら,この程度の実装でよい.
- javax.xml.rpc.encoding.Serializerとorg.apache.axis.encoding.Serializerを実装する.
- どうも両方実装しないとコンパイルが通らないとかClassCastExceptionなどの問題が生じる.
- getMechanismTypeメソッドの実装
- 多分ほとんどorg.apache.axis.Constants.AXIS_SAXを返していればよい.
- serializeメソッドの実装
- カスタムシリアライザ作成のメイン.
- シリアライズ対象を表す要素の開始と終了は
context.startElement(name, attributes);
とcontext.endElement();
を自分で呼び出す. - 上記メソッド呼び出しの間に子要素出力処理を記述.
- 子要素出力処理は,基本的に
org.apache.axis.encoding.SerializationContext#serializer
の呼び出しに持ち込む. あとはSerializationContextがやってくれる. - 上記serializeメソッド呼び出し用のorg.xml.sax.Attributesオブジェクトは,新規に作成. Serializer#serializeの引数のものは,シリアライズ対象の要素のものなので,使用しない. また,SerializationContext#serializerがいろいろしてくれるので,作成した新規のAttributesは基本的に空でよい.
- シリアライズ対象を表す要素の開始と終了は
以下にサンプルのカスタムデシリアライザ,HogeDeserializerを示す.
カスタムデシリアライザは
org.apache.axis.encoding.DeserializerImplを拡張して実装する. ポイントは以下である.
- コールバックメソッドの実装
- 基本的な仕組みは,SAXを発展させたようなものである. デシリアライズ処理内容に応じて,コールバックを実装する.
- メンバvalueの作成
- 上位は,Deserializerによる処理結果をgetValueを通して出力する. すなわち,各種コールバックは,基本的にメンバvalueを生成,設定,操作してデシリアライズ処理の結果を出力する.
- startElement
- startElementメソッドは,デシリアライズ対象ノードの開始タグで呼び出される.
- onStartChild
- onstartchildメソッドは,デシリアライズ対象ノードの子要素の開始タグ毎に呼び出される.
- org.apache.axis.encoding.DeserializationContext
- SerializationContextと同様,DeserializationContextはデシリアライズ時のユーティリティである. 難しい処理,面倒臭い処理は,こいつが面倒見てくれるので,うまく活用する.
以下にサンプルのクライアントを示す.
ポイントは,
シリアライザ,デシリアライザの指定にはtypeMapping要素を記述する.
call.registerTypeMapping(Hoge.class, qn, HogeSerializerFactory.class, HogeDeserializerFactory.class);における,カスタムシリアライザとカスタムデシリアライザのファクトリ指定である. サーバ側では,wsddを記述する.
<typeMapping
xmlns:axissample="http://www.fireproject.jp/ns/axissample/hoge"
qname="axissample:hoge"
languageSpecificType="java:org.fireproject.axissample.Hoge"
serializer="org.fireproject.axissample.HogeSerializerFactory"
deserializer="org.fireproject.axissample.HogeDeserializerFactory"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
各属性の説明を以下に示す.
- qname
- デシリアライズ対象の要素のqnqme.
- languageSpecificType
- シリアライズ対象の言語とクラス. typeMappingは,qnameとlanguageSpecificTypeのマッピングである.
- serializerとdeserializer
- それぞれのファクトリクラス. シリアライザ,デシリアライザそのものではなく,ファクトリである点に注意.
- encodingStyle
- よくわからない.
多分
"http://schemas.xmlsoap.org/soap/encoding/"
でよい.
jwsなので,デプロイ後一度はjwsに要求して,コンパイルしてもらう必要がある.
$> java -jar axissample.jar http://localhost:8180/fireproject/HogeFactory.jws decrypt [.eulaVterces si sihT] org.fireproject.axissample.Hoge@1fe88d [updated = false; updateMessage = null; secretValue = This is secretValue.; ] encrypt[This is secretValue.] decrypt [.eulaVterces si sihT] org.fireproject.axissample.Hoge@178460d [updated = true; updateMessage = HogeFactory updated this hoge.; secretValue = This is secretValue.; ] $> java -jar axissample.jar http://localhost:8180/fireproject/services/Hoge decrypt [.eulaVterces si sihT] org.fireproject.axissample.Hoge@1fe88d [updated = false; updateMessage = null; secretValue = This is secretValue.; ] encrypt[This is secretValue.] decrypt [.eulaVterces si sihT] org.fireproject.axissample.Hoge@178460d [updated = true; updateMessage = HogeFactory updated this hoge.; secretValue = This is secretValue.; ]encrypt,decryptメソッドのパラメータから,うまくカスタムシリアライザ,デシリアライザが機能していることが分かる. また,送受信電文では,HogeオブジェクトのsecretValueの値が逆順で記述されていた.

