Apache SOAP型マッピング: 第2回 シリアライゼーションの詳細説明書

ユーザー独自のシリアライザーおよびデシリアライザーの作成手順

SOAPは、データベース、プログラム言語 (例えばJavaプログラム言語)、およびデータ・リポジトリーにおける共通の型を表すためのエンコード方式を指定しています。Apache SOAPのツールキットは、Javaの型を直列化されたXML表現にマップするという、厄介な仕事を行なうクラスである(デ)シリアライザー の基本セットを提供することにより、エンコードをサポートします。この2回シリーズの記事の第1回では、これらの(デ)シリアライザーの使い方を調べました。この第2回で、Gavin Bongは、ツールキットから提供される(デ)シリアライザーがユーザーの要求を満たすことができない場合に、ユーザー独自の(デ)シリアライザーを作成する方法を示します。彼はまた、このシリーズで研究する概念の多くをデモンストレーションする、サンプル・アプリケーションを提供しています。

Gavin Bong (gavinb@eutama.com), Software Engineer, eUtama Sdn. Bhd.

Gavin Bong氏は、マレーシアのクアラルンプール出身のJava開発者です。氏は、サービス指向のアーキテクチャーとワイヤレスJavaに関心を持っています。同氏の連絡先はgavinb@eutama.com です。図1を完成するに当たってYing Pee Eng氏の協力に感謝しています。



2002年 3月 01日

このシリーズの第1回の記事では、SOAPがどのようにしてデータ型をXMLにマップするのかを示し、Apache SOAPツールキットに組み込まれているシリアライザーおよびデシリアライザー (以後、両者をまとめて「(デ)シリアライザー」と呼びます) の使用方法を示しました。今回は、ユーザー独自の(デ)シリアライザーを作成するための調理法を紹介することにします。参照のために、いくつかの基本(デ)シリアライザーの元になる素材を用意しておくとよいでしょう。また、型マッピングがシステム内でどのように解決されるのかを再確認するために、第1回の『型マッピングのパターン』のセクションを読み返してください。

調理法の説明の後で、スキーマで制約されたSOAPをインプリメントする簡単なアプリケーションを紹介します。このアプリケーションが行なう通信においては、セクション4エンコード方式に準拠しない購入注文文書を、意図的にSOAPを使用して送信しています。

ルートおよび通常の(デ)シリアライザー

Apache SOAPツールキットにバンドルされた(デ)シリアライザーが、いずれもユーザーのJavaクラスに使えない場合には、ユーザー自身でカスタム・(デ)シリアライザーを作成する必要があります。まず、私がルート・(デ)シリアライザー と呼んでいるものと、通常の(デ)シリアライザー と呼んでいるものを区別していただく必要があります。RPCのパラメーターおよび応答のシリアライゼーションとデシリアライゼーションの初期ブートストラッピングは、ルート・(デ)シリアライザーによって処理されます。表1 に、Apache SOAPにおける3つのルート・(デ)シリアライザーをリストしておきます。

表1. ルート・(デ)シリアライザー
エンコーディング・スタイル(デ)シリアライザー
セクション5ParameterSerializer
リテラルXMLXMLParameterSerializer
XMIXMIParameterSerializer

該当のルート・(デ)シリアライザーは、encodingStyle と、クラスParameter (シリアライゼーションの場合)、またはQNameSOAP-ENV:Parameter (デシリアライゼーションの場合) との2つに基づいてディスパッチされます。実際のディスパッチングがどのように行なわれるのかを知るためには、クライアント・サイドにおけるJavaタイプのシリアライゼーションに至る、一連のイベントを理解しておく必要があります。

  Call call = new Call();
...
  resp = call.invoke(url, ""); //1

上記の行1 (//1) でCall クラスのinvoke メソッドが呼び出されると、Call クラスは、関連付けられたパラメーターを繰り返して処理します。

org.apache.soap.rpc.RPCMessage:
...
  Serializer ser = xjmr.querySerializer(Parameter.class, actualParamEncStyle); //2
  ser.marshall(...);
...

それぞれのパラメーターごとに、タイプをマップするレジストリーが照会され、その後で、戻されたシリアライザーのmarshall() メソッドが呼び出されます。行2で戻されるシリアライザーはルート・シリアライザーです。

ここで、Webサービスにおけるデシリアライゼーション・プロセスに注目してみましょう。サーバー・サイドでは、SOAP RPCメッセージのリスナーはサーブレットとしてインプリメントされています。doPost メソッドはSOAP要求を検索し、それをもとにCall オブジェクトの再構成を試みます。

org.apache.soap.rpc.RPCMessage:
...
  Bean paramBean = smr.unmarshall(actualParamEncStyle, RPCConstants.Q_ELEM_PARAMETER
...); //3
  Parameter param = (Parameter)paramBean.value;
...

行3では、RPCConstants.Q_ELEM_PARAMETER の値はSOAP-ENV:Parameter となります。ルート・デシリアライザーへのディスパッチングが行なわれるのは、unmarchal() メソッドが呼び出されたとき、すなわちこの行3においてです。

次に、ルート・(デ)シリアライザーは、タイプをマップするレジストリーを照会し、次に呼び出す通常の(デ)シリアライザーを探し出します。この呼び出しは、(シリアライゼーションの実行中に) レジストリーがプリミティブJavaタイプに対する(デ)シリアライザーを戻すとき、または (デシリアライゼーションの実行中に) XMLエレメントが単純タイプに対するコンテナーであるときにだけ開始されます。

提供された通常の(デ)シリアライザー (これらは、パッケージorg.apache.soap.encoding.soapenc に収められています) の大部分は、Apache SOAPにおけるほとんどのヘルパー・クラスと同様に、セクション5のエンコード方式を処理します。私がセクション5のエンコード方式による(デ)シリアライザーに焦点をしぼって説明するのは、このためです。

図1. (デ)シリアライザーを作成するためのAPI
図1. (デ)シリアライザーを作成するためのAPI

シリアライザーの調理法

シリアライザーはorg.apache.soap.util.xml.Serializer をインプリメントし、単一のメソッドを認識します。

  void marshall(
    java.lang.String inScopeEncStyle, 
    java.lang.Class javaType, 
    java.lang.Object src, 
    java.lang.Object context, 
    java.io.Writer sink, 
    NSStack nsStack, 
    XMLJavaMappingRegistry xjmr, 
    SOAPContext ctx) 
      throws java.lang.IllegalArgumentException, 
             java.io.IOException

次に、marshall() の各パラメーターについて調べてみましょう。

  • inScopeEncStyle: これは、外側のCall またはResponse オブジェクトで指定されたとおりにencodingStyleURI を表します。
  • javaType: これは、直列化されるオブジェクトの実行時タイプです。
  • src: これは、直列化されるJavaオブジェクトへの参照です。
  • context: アクセサー名を記述するString です。このシリアライザーがParameterSerializer によって呼び出される場合、コンテキスト値は、(SOAPクライアントで宣言された)Parameter クラス内の名前付きプロパティーと等価になるか、あるいはこれがSOAPサーバーの場合にはreturn にハードコーディングされます。これは、非ヌルでなければなりません。
  • sink: SOAP XMLインスタンスが書き込まれる宛先シンク。
  • nsStack: 現在の有効範囲に含まれているネームスペース宣言のスタックをインプリメントするデータ構造。
  • xjmr: これは、Javaタイプに基づいて次に使用するシリアライザーを照会するために使用する、smr です。javaType およびencodingStyle に基づいて他のシリアライザーに代行させるために、xjmr マーシャル・メソッドも呼び出します。例えば、HashtableVector などの複合構造体の場合には、これを行う必要があります。
  • ctx: これは、サーブレット・コンテキストからjavax.servlet.http.HttpServletRequestjavax.servlet.http.HttpSession などを渡すために使用されます。

marshall() メソッドの使用法は、次のとおりです。

ステップ1: 新規のネームスペース有効範囲を作成する

   nsStack.pushScope();

XMLのネームスペース宣言の有効範囲を管理するには、このNSStack クラスを使用してください。後にこのメソッド内でNSStack を使用することにより、新規ネームスペースを追加したり、スタックからURIが指定された接頭部を探し出したりすることができます。

ステップ2: オブジェクト引数に対する制約を検査する

シリアライゼーションが行なわれるためには、2つの条件が満たされる必要があります。つまり、シリアライザーが、サポートされるタイプになっていなければならず、また、直列化されるオブジェクトが非ヌルでなければなりません。次のコードは、これらの制約がVectorSerializer に課せられるようすを表しています。

     if ( (src != null) &&
         !(src instanceof Vector) &&
         !(src instanceof Enumeration))
              throw new IllegalArgumentException("Tried to pass a '" +
                      src.getClass().toString() + "' to VectorSerializer");

組み込みシリアライザーのうちのいくつかは、次のように、javaType パラメーターと予想されたタイプを実際に比較します。

  if(!javaType.equals(Foo.class)) ...

ただし、この技法を使用することはお勧めしません。タイプラベル不一致のバグの影響を招きやすいためです (参考文献を参照してください)。

ステップ3: ヌル・アクセサーを生成する

オブジェクト引数がヌルの場合、そのタイプに対応するヌル・アクセサーを生成する必要があります。

  SoapEncUtils.generateNullStructure(inScopeEncStyle,
javaType, context, sink, nsStack, xjmr);

ステップ4: オブジェクトを直列化する

オブジェクトをセクション5に準拠するSOAP XML文書に直列化するには3つのステップが必要であり、アクセサーのための開始エレメントの生成、オブジェクトの値の直列化、およびエレメントの終了を行います。

最初のステップは、次のユーティリティー・メソッドを呼び出すことによって、簡単に行なうことができます。

  SoapEncUtils.generateStructureHeader(inScopeEncStyle,
         javaType,
         context,
         sink,
         nsStack,xjmr);

このコードは、queryElementType を呼び出して、javaType 用にマップされたQName を検索します。

  <context xsi:type="QName">

オブジェクト引数src が単純タイプである場合には、2番目のステップであるオブジェクトの値の直列化は、単純に、src.toString() メソッドを呼び出してそれを書き出すだけで済みます。それ以外の場合、オブジェクトを構成する各部分を識別し、それらをよりプリミティブなシリアライザーに個別に渡す必要があります。組み込みシリアライザーのソースを調べると、これらの構成部分を多くの方法で識別できることが分かります。

  • Javaリフレクション (例えば、BeanSerializer)
  • List データ構造の反復 (例えば、ArraySerializer)
  • クラスについての事前知識による直接アクセス (つまり、シリアライザーが1つの特定クラスだけを操作することがあらかじめ分かっている場合)

その他のシリアライザーを識別すると、次のような呼び出しを行なってそれらに代行させることができます。

  xjmr.marshall(inScopeEncStyle,
                componentType,
                componentValue,
                accessorName,
                sink, nsStack, ctx);

ここで、componentTypecomponentValue はそれぞれ、オリジナルのsrc パラメーターの構成部分に関する実行時タイプとオブジェクトの参照を表しています。marshall() メソッドは、関連するシリアライザーを検索するために実際にquerySerializer を呼び出し、その後で関連するシリアライザーのmarshall() メソッドを呼び出します。いうまでもなく、この方法を使用できるのは、タイプをマップするレジストリー内のすべてのコンポーネントに関するシリアライザーを登録してある場合にかぎります。

最後のステップであるエレメントの終了は、アクセサーの終了タグを書き出すだけで完了させることができます

  sink.write("</" + context + '>');

最後に、現行のネームスペース有効範囲を終了させて、クリーンアップしなければなりません。

  nsStack.popScope();

デシリアライザーの調理法

デシリアライザーはorg.apache.soap.util.xml.Deserializer をインプリメントし、単一のメソッドを認識します。

  Bean unmarshall(
    java.lang.String inScopeEncStyle, 
    QName elementType, 
    org.w3c.dom.Node src, 
    XMLJavaMappingRegistry xjmr, 
    SOAPContext ctx)

unmarshall() メソッドの目的は、パラメーターをJavaオブジェクトとして再構成することです。そのためには、src DOMノードによって組み込まれているXMLフラグメントを処理する必要があります。そのためのプログラミング・モデルとしては、org.apache.soap.utils.xml.DOMUtils 内で、タイプをマップするレジストリーと一緒にDOMラッパー・メソッドを使用するとよいでしょう。一般に、デシリアライゼーションにおけるDOMUtils は、シリアライゼーションにおけるSoapEncUtils に相当します。

src に含まれているXMLには、複数参照値が含まれないことが保証されているという点に注目してください。すべての複数参照href は、ルート・デシリアライザーParameterSerializer によって解決され、実際の値に戻されています。

したがって、デシリアライザーの調理法は次のようになります。

ステップ1: ヌルを検査する

次のようにして、属性がヌルであるかどうかを検査するとよいでしょう。

    Element root = (Element)src;
    if (SoapEncUtils.isNull(root))
    {
        return new Bean(Your.class, null);
    }

ステップ2: Javaオブジェクトを再構成する

Javaオブジェクトを再構成するプロセスは、そのデータ型がどのカテゴリーに属するのかによって異なります(これらの型カテゴリーの詳細については、第1回を参照してください)。

単純タイプ
単純タイプをデシリアライゼーションする場合には、戻されるオブジェクトを初期化するためにそれを使用する前に、DOMUtils.getChildCharacterData(Element) を使用してsrc というストリング値を検索し、オプションとしてそのストリング値を再処理してください (例えば、"NaN" をFloatDeserializer 内のFloat.NaN にマップします)。

複合タイプ
複合タイプは、2つのカテゴリーに大別されます。最初のカテゴリーは、エレメントが反復される同一構造のタイプからなります。例えば、java.util.List およびjava.util.Map をインプリメントするJava配列およびクラスがこれに当たります。もう1つのカテゴリーは、任意の構造を示すその他のすべてのJavaクラスを表すものです。したがって、デシリアライゼーション・プロセスとは結局、次のように、XML構造をナビゲーションして関係のある子孫エレメントを識別したうえで、デシリアライゼーション処理をよりプリミティブなデシリアライザーに代行させることにほかなりません。

  • DOMのナビゲート最初のカテゴリーの複合タイプを扱う場合には、DOMUtils.getFirstChildElement() およびDOMUtils.getNextSiblingElement() を使用して、そのすべての反復メンバーをナビゲートしてください。それ以外の場合には、DOM APIを使用して、メンバー・プロパティーを表すエレメント を識別してください。
  • 他のデシリアライザーへのデシリアライゼーションの代行最初に、SOAPタイプを抽出する必要があります。
    QName soapType = SoapEncUtils.getTypeQName(rootElement);

    次に、さらにプリミティブなデシリアライザーに代行させます。

    xjmr.unmarshall(inScopeEncStyle, soapType, rootElement, ctx);

    xjmr.unmarshall は内部的にqueryDeserializer を呼び出し、戻されたデシリアライザーでunmarshall を起動します。上記の2つのステップは、デシリアライゼーションをParameterSerializer に代行させることにより、1つにまとめることができます。これが行なわれるのは、xsi:type 属性が抜けている場合に、私たちが、soapType をQName{""}/X に設定して (このXは、ルート・エレメントのtagName です)xjmr.unmarshall() を起動しようとするからです。これを行なうためのコードは、すでにParameterSerializer.unmarshall() の中に便利な形でパッケージ化されているため、このプロセスを短縮すると次のようになります。

    Bean paramBean = xjmr.unmarshall(inScopeEncStyle,
                                    RPCConstants.Q_ELEM_PARAMETER,
                                    rootElement, ctx);
  • ターゲット・オブジェクトの初期化ターゲット・オブジェクト は、再構成の対象となるオブジェクト・インスタンスです。メンバー・プロパティーがデシリアライゼーションされた後で、次のようにターゲット・オブジェクトでmutatorメソッドを起動して、メンバー・プロパティーの値を復元することができます。
      Foo foo = new Foo();
      foo.setS( paramBean.value );

ステップ3: 再構成されたオブジェクトを戻す

Bean クラスは、実行時タイプと実際に戻されたインスタンスをカプセル化します。デシリアライザーは、ほとんどの場合、特定のクラスに特有ですので、どのクラスを戻すべきかを認識します。BeanSerializerArraySerializer などの一般的なデシリアライザーの場合、タイプのマップにおいてjavaType プロパティーが、戻されるタイプを伝えます。

   return(new Bean(Foo.class, foo));

ルート・(デ)シリアライザーの登録

カスタムencodingStyles を導入したい場合には、ルート・(デ)シリアライザーを作成しなければならないということはすでに述べました。ルート・(デ)シリアライザーは、1つの小さな相違点を除き、通常の(デ)シリアライザーと同じ方法でインプリメントされます。その相違点とは、すべてのルート・(デ)シリアライザーが、特別に設計されたQNameおよびJavaタイプを使用してタイプをマップするレジストリーに登録される、ということです。このQNameおよびJavaタイプは、Apache SOAPに対し、encodingStyle プロパティーに基づいて(デ)シリアライゼーション・プロセスをブートストラップするように指示します。下記のサンプル・コードの、強調表示された値に注意してください。ルート・(デ)シリアライザーを登録するときには、これらの値を使用する必要があります。

  [Client]
    smr.mapTypes(customEncURI,
RPCConstants.Q_ELEM_PARAMETER,
Parameter.class,
      customSerializer, null);
  [Server]
    <isd:map encodingStyle="customEncURI"
      xmlns:x="http://schemas.xmlsoap.org/soap/envelope" qname="x:Parameter"
      javaType="org.apache.soap.rpc.Parameter"
      java2XMLClassName="foo.customSerializer" />

スキーマに制約されたSOAP

このセクションでは、複雑なタイプを(非)直列化するための、BeanSerializer の代替ソリューションについて説明します。この技法 (スキーマに制約されたSOAP と呼ぶことにします) では、RPCパラメーターのリテラルXML構造を記述するためにXMLスキーマを使用します。ここでは、クライアントおよびサーバー上のデータ・モデルにかかわらず、メッセージの形式に厳密に従って相互操作することにします。混乱を避けるために、RPC呼び出しは引き続きセクション5を使用してエンコードされますが、パラメーターはそうではないということに注意する必要があります。

この技法を、サンプル・アプリケーションを使用して説明します。後述する参考文献から、その完全なコードをダウンロードすることができます。クライアントはWebサービスに購入注文を送信し、Webサービスが確認通知ストリングでそれに応答します。したがって、このWebサービスによってエクスポートされるメソッド・シグニチャーは、次のようになります。

public String eatPo (PurchaseOrder p);

この技法が機能するためには、XML/ オブジェクトのデータ結合フレームワークが必要です。この例では、ExolabのCastorツールキットを使用することにします(Castorへのリンクおよびその他の、JSX、JAXB、Schema2Javaなどのシリアライゼーション・フレームワークのリストについては、後述する参考文献セクションを参照してください)。

この技法のステップは、次のとおりです。

  1. PurchaseOrder のためのXML形式について合意する。
  2. Castorを使用してJavaクラスを生成する。
  3. カスタム・(デ)シリアライザーを作成する。
  4. 各クライアントおよびサーバーのためのタイプのマップ・コードを記述する

ステップ1: PurchaseOrderのためのXML形式について合意する

このユース・ケースでは、単純化のためにPurchaseOrder スキーマからオーダー詳細情報セクションを除去しました。また、PONumber 属性により、このスキーマがセクション5のエンコード方式に準拠しなくなっていることに注意してください。

図2. PurchaseOrder.xsd
図2. PurchaseOrder.xsd

ステップ2: Castorを使用してJavaクラスを生成する

CastorのSourceGenerator コマンド行ツールを実行して、PurchaseOrder.xsd 内のスキーマをインプリメントするJavaクラスを生成します。

  java org.exolab.castor.builder.SourceGenerator
     -i PurchaseOrder.xsd
     -package com.raverun.po.castor

SourceGenerator ツールは、最新のスキーマ・ネームスペースであるhttp://www.w3.org/2001/XMLSchema だけを認識します。

次に、Javaクラスのセットをコンパイルします。生成されたファイルはSAX 1.0 APIを使用しますので、-deprecation オプションを使用する必要があります。このような手作業のコンパイルを避けるために、Exolabでは、コンパイルを自動化するためのAnt taskdefを開発中です。

ステップ3: カスタム・(デ)シリアライザーを作成する

次に、PurchaseOrder クラスで示された対応メソッドを利用して、PurchaseOrderSerializer において(デ)シリアライゼーション・メソッドをインプリメントします。シリアライゼーションの場合、 PurchaseOrderjava.io.Writer またはorg.xml.sax.DocumentHandler に合わせてマーシャルすることができます。 リスト1 に示すように、PurchaseOrdermarshal() メソッドにシリアライゼーションを代行させます。1つ注意しなければならないことがあります。それは、 marshal() メソッドによって生成されたXMLストリームにはXMLプロローグが含まれる、ということです。 PurchaseOrderSerializer は、java.io.FilterWriter であるFilterXmlPrologsink をラッピングすることにより、このプロローグを除去します。 リスト2 には、デシリアライゼーション・プロセスにおいて発生し得るいくつかの例外ケースが含まれています。

リスト1. PurchaseOrderSerializer内のmarshal() メソッドからの抜粋
      ----o<---------
      SoapEncUtils.generateStructureHeader(inScopeEncStyle,
                                         javaType,
                                         context,
                                         sink,
                                         nsStack,
                                         xjmr);
      PurchaseOrder po = (PurchaseOrder)src; try{
        po.marshal( new FilterXmlProlog(sink) );
      }catch(Exception e){ throw (new java.io.IOException("Castor: Error marshalling"));
      }
      sink.write( StringUtils.lineSeparator );
      sink.write("</" + context + '>');
      ----o<---------
リスト2. PurchaseOrderSerializerにおけるデシリアライゼーション中の例外ケース
    (b1) Null PO.
                 ---------------------------
         <po xmlns:ns2="urn:raverun" xsi:type="ns2:po"
           xsi:null="true"/>
         ---------------------------
    (b2) Non null but nothing submitted in the body.
         ---------------------------
         <po xmlns:ns2="urn:raverun" xsi:type="ns2:po" />
         ---------------------------
    (b3) PO that violates the schema.
         ---------------------------
         <po xmlns:ns2="urn:raverun" xsi:type="ns2:po">
           <foo bar="123"/>
         </po>
         ---------------------------

ステップ4: 各クライアントおよびサーバーのためのタイプのマップ・コードを記述する

最後に、カスタム・(デ)シリアライザーを参照するためにタイプのマップ・コードを宣言する必要があります。PurchaseOrder のためのエンコード方式としてセクション5が指定されているのは、読者にとって意外かもしれません。これは、使いやすさを考慮したためです。このようにすると、ParameterSerializer を使用して、デシリアライゼーション・プロセスをブートストラップしたり、シリアライゼーション・コード内でSoapEncUtils を使用したりすることができます。

  [Client]
    SOAPMappingRegistry smr = new SOAPMappingRegistry();
    smr.mapTypes(Constants.NS_URI_SOAP_ENC,
                   new QName("urn:raverun", "po"),
                   PurchaseOrder.class, pos, null);
  [Server]
    <isd:map
       encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
       xmlns:x="urn:raverun" qname="x:po"
       javaType="com.raverun.po.castor.PurchaseOrder"
       xml2JavaClassName="com.raverun.po.PurchaseOrderSerializer" />

このソリューションの潜在的な問題

スキーマに制約されたSOAPの例を検討する際には、以下の問題に注意してください。

  • 標準に準拠するためには、<po> エレメントにおけるセクション5のエンコード方式に関して何も指定しないでださい(より仕様に準拠したSOAP XMLインスタンスについては、リスト3 を参照してください)。SOAP 1.1仕様 (参考文献を参照) では、この要件が次のように記述されています。

    ゼロ長のURI ("") の値は、含まれているエレメントのエンコード・スタイルについて何も指定されていないことを明示的に示す。

    ヌルのencodingStyle に対する代替方式として、ユーザーの通信ニーズに合わせて調整したカスタムencodingStyleURI を導入するという手段があります。

  • Castorには、注意すべきバグがいくつかありますが、すべてのバグには回避策が設けられています。0.9.3よりも古いバージョンのCastorを使用している場合には、スキーマ妥当性検査を予期したとおりに行なうことができません。解決策は、最新リリースにアップグレードすることです。その一方で、Castor 0.9.3 (私が使用したバージョン) は、標準出力ストリームに誤ったメッセージを生成します。私が受け取ったメッセージは次のようなものです。

              Warning : preserved is a bad entry for the whiteSpace value.

    Castorの最新バージョン0.9.3.9では、この警告は生成されません。

  • PurchaseOrderSerializer は、複数参照値には直列化されません。ただし、複数参照値の非直列化は、正しく行ないます。これはPurchaseOrderSerializer 自体の機能ではなく、ParameterSerializer の機能です。
リスト3. より仕様に準拠したSOAPインスタンス
<ns1:eatPo xmlns:ns1="urn:poservice" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <po xmlns:ns2="urn:raverun" xsi:type="ns2:po"
    SOAP-ENV:encodingStyle="">
    <purchaseOrder xmlns="http://www.example.com/PO1">
      <header PONumber="9999-1212">
        <Date>2001-09-25T14:40:13.453</Date>
      </header>
      ...
    </purchaseOrder>
  </po>
</ns1:eatPo>

最新のインターフェース変更

Apache SOAPの最新の公式リリース (バージョン2.2) は2001年3月に登場しました。開発の焦点はAxis (現在はベータ1) に移っていますが、バグ修正は引き続き行なわれています。私たちは2.3リリース (そういうものがあれば) を待っているのですが、公式リリースのユーザーは、特にSOAPMappingRegistry およびその関連クラスについて、コードベースで大きな更新が行なわれたことに注意する必要があります。これらの修正との連係操作を行うには、既存のコードに何らかの変更を加える必要があるでしょう。

注意すべき変更内容を以下にリストします。

  • スキーマ・ネームスペースが、デフォルトで2001勧告のネームスペースを参照するようになりました。バージョン2.2では、1999ネームスペースを参照していました。
  • したがって、SOAPMappingRegistry をその引数なしコンストラクターによってインスタンス化すると、2001ネームスペースを認識するインスタンスが戻されます。
  • SOAPMappingRegistry のインスタンス作成が、静的ファクトリー・パターンに合わせて再設計されました。したがって、コンストラクターSOAPMappingRegistry(schemaURI) をオーバーロードする代わりに、ファクトリー・メソッドgetBaseRegistry(schemaURI) を使用するようにしてください。
      public static SOAPMappingRegistry getBaseRegistry (String schemaURI);
  • バージョン2.2では、チェーン・レジストリーの機能が提供されています。最近、以下のメソッドが追加されました。
      public SOAPMappingRegistry(SOAPMappingRegistry parent);
      public SOAPMappingRegistry(SOAPMappingRegistry parent, String schemaURI);
      public SOAPMappingRegistry getParent()
      public String getSchemaURI()

    タイプのマップを解決する場合には、一致するものが見つかるまで、そのチェーンをたどって行なわれます。
  • DeploymentDescriptor クラスは、タイプのマップ宣言でオプションの属性としてqname 属性を扱います。

結論

今回の記事の例により、このシリーズの第1回の記事で概要を示した理論的な概念が明瞭になったことを期待しています。ネットワーク上の多くのマシンを使用して運用されるWebサービスを現実のものとして広く行き渡らせるためには、開発者は、プログラムで扱うオブジェクトが、あるマシンから別のマシンにどのように伝送されるのかを理解していなければなりません。SOAPにおけるタイプのマップ機能をよく理解しておくと、よりすぐれた分散アプリケーションおよびサービスを構築しやすくなります。

参考文献

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=SOA and web services, Java technology
ArticleID=297186
ArticleTitle=Apache SOAP型マッピング: 第2回 シリアライゼーションの詳細説明書
publish-date=03012002