Apache CXFのJAX-WS動的Webサービス・クライアントを利用する


Apache CXFのJAX-WS動的Webサービス・クライアントの利用方法を紹介します。

CXFについて初めての方は、次の記事を参考にして下さい。

CXFの動的Webサービス・クライアントの話に入る前に、JAX-WSのごく一般的なWebサービスの呼び出し方法について簡単に説明します。手順をまとめると、次のようになります。

  1. WSDL(公開しているWebサービスに関する仕様をまとめたXML文書)を取得する
  2. wsimportコマンドでWSDLからプロキシコード(*)を生成する
    (*) サービスクラス、SEI(Service Endpoint Interface)、  オペレーション引数/戻り値の型クラス、 ObjectFactoryクラスが生成されます
  3. 生成したプロキシコードを利用してwebサービスを呼び出す

プロキシコードを利用した呼び出しコードは、次のようなコードになります。

...
HogeService service = new HogeService();
Hoge port = service.getHogePort();
オペレーション戻り値 result = port.fuga(オペレーション引数);
... 


この手順でWebサービスの呼び出しを行う場合は、wsimportコマンドで生成したクラスファイルをクラスパス上に配置する必要があります。

以上が、一般的なWebサービスの呼び出し方法です。

次にCXFの動的Webサービス・クライアントの利用法について説明します。CXFの動的Webサービス・クライアントを利用することで、先ほど説明した手順.2を省略してWebサービスの呼び出しを行うことができます。(正確には手順.2で行っていることをCXFが動的に行っているため、利用者はwsimportの手間を省くことができる。)

CXFの動的Webサービス・クライアントを利用した呼び出しコードは、次のようになります。

...
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient(WSDLのURLまたはファイル名);
Object[] result = client.invoke("オペレーション名",  オペレーション引数);
...


動的Webサービス・クライアントを利用することで、WSDLの内容に変更があった場合もプロキシコードの再生成や置換を意識する必要がありません。(Webサービスの仕様についての変更点は意識しないといけませんね・・・)

ただし、オペレーションの引数型/戻り値型がプリミティブ型、ラッパクラス、コレクション以外の場合は、型クラスのFQCNを指定してクラスローダから動的にインスタンス生成を行う必要があるため、注意する必要があります。

例えば、オペレーションの引数の型が data.Productの場合、次のようなコードを書く必要があります。

...
JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient("http://localhost:8080/hoge/ProductService?wsdl");

// JaxWsDynamicClientFactory#createClient()を実行した際に
// クラスパス上にプロキシコードのクラスが生成される.
// よって、クラスローダからオペレーションの引数の型(data.Product)を
// ロードし、インスタンスを生成する必要がある.
Object product = Thread.currentThread().getContextClassLoader().loadClass("data.Product").newInstance();

// 値の設定
Method m = product.getClass().getMethod("setName", String.class);
m.invoke(product, "Mac Book Pro");

client.invoke("addProduct", product);
...



少々、面倒ですね。

サンプルコード

https://github.com/rising3/cxf-jaxws-dynclientから取得できます。

あわせてお読みください