web-dev-qa-db-ja.com

CXFまたはJAX-WSで生成されたWebサービスクライアントでWSDLの場所を指定する必要を回避する方法

CXFからwsdl2Javaを使用して(wsimportに似たものを生成する)Webサービスクライアントを生成すると、mavenを介して、私のサービスは次のようなコードで始まります。

@WebServiceClient(name = "StatusManagement", 
                  wsdlLocation = "c:/some_absolute_path_to_a_wsdl_file.wsdl",
                  targetNamespace = "http://tempuri.org/") 
public class StatusManagement extends Service {

    public final static URL WSDL_LOCATION;
    public final static QName SERVICE = new QName("http://tempuri.org/", "StatusManagement");
    public final static QName WSHttpBindingIStatus = new QName("http://tempuri.org/", "WSHttpBinding_IStatus");
    static {
        URL url = null;
        try {
            url = new URL("c:/some_absolute_path_to_a_wsdl_file.wsdl");
        } catch (MalformedURLException e) {
            System.err.println("Can not initialize the default wsdl from c:/some_absolute_path_to_a_wsdl_file.wsdl");
            // e.printStackTrace();
        }
        WSDL_LOCATION = url;
    }

ハードコードされた絶対パスは本当にひどいものです。生成されたクラスは、私以外のコンピューターでは機能しません。

最初のアイデアは、WSDLファイル(およびインポートするすべてのもの、他のWSDL、XSD)をjarファイルのどこかに置き、クラスパスにすることです。しかし、私たちはこれを避けたいです。そのすべてがWSDLおよびXSDに基づいたCXFおよびJAXBによって生成されたため、実行時にWSDLを知る必要はありません。

WsdlLocation属性は、WSDLの場所をオーバーライドすることを目的としています(少なくともこれはどこかで読んだものです)。デフォルト値は ""です。 Mavenを使用しているため、CXFの構成内に<wsdlLocation></wsdlLocation>を含めて、ソースジェネレーターにwsdlLocationを空白のままにしようと試みました。ただし、これはXMLタグが空なので、XMLタグを無視するだけです。 <wsdlLocation>" + "</wsdlLocation>を使用して、ひどく恥ずべきハックを行いました。

これにより、他の場所も変更されます。

@WebServiceClient(name = "StatusManagement", 
                  wsdlLocation = "" + "",
                  targetNamespace = "http://tempuri.org/") 
public class StatusManagement extends Service {

    public final static URL WSDL_LOCATION;
    public final static QName SERVICE = new QName("http://tempuri.org/", "StatusManagement");
    public final static QName WSHttpBindingIStatus = new QName("http://tempuri.org/", "WSHttpBinding_IStatus");
    static {
        URL url = null;
        try {
            url = new URL("" + "");
        } catch (MalformedURLException e) {
            System.err.println("Can not initialize the default wsdl from " + "");
            // e.printStackTrace();
        }
        WSDL_LOCATION = url;
    }

だから、私の質問は:

  1. すべてのクラスがCXFおよびJAXBによって生成された場合でも、本当にWSDLの場所が必要ですか?はいの場合、なぜですか?

  2. WSDLの場所が本当に必要ない場合、CXFがそれを生成せず、完全に回避しないようにする適切でクリーンな方法は何ですか?

  3. このハックで得られる悪影響は何ですか?まだ何が起こるかを確認するためにそれをテストすることはできませんので、誰かが事前に言うことができれば、それは素晴らしいでしょう。

151
Victor Stafusa

今日、ついにこの質問に対する正しい答えを見つけました。

<plugin>
    <groupId>org.Apache.cxf</groupId>
    <artifactId>cxf-codegen-plugin</artifactId>
    <version>${cxf.version}</version>
    <executions>
        <execution>
            <id>generate-sources</id>
            <phase>generate-sources</phase>
            <configuration> 
                <sourceRoot>${project.build.directory}/generated-sources/cxf</sourceRoot>
                <wsdlOptions>
                    <wsdlOption>
                        <wsdl>${project.basedir}/src/main/resources/wsdl/FooService.wsdl</wsdl>
                        <wsdlLocation>classpath:wsdl/FooService.wsdl</wsdlLocation>
                    </wsdlOption>
                </wsdlOptions>
            </configuration>
            <goals>
                <goal>wsdl2Java</goal>
            </goals>
        </execution>
    </executions>
</plugin>

wsdlLocationの値の先頭にclasspath:が付いていることに注意してください。これは、wsdlが絶対パスではなくクラスパス上にあることをプラグインに伝えます。次に、次のようなコードが生成されます。

@WebServiceClient(name = "FooService", 
                  wsdlLocation = "classpath:wsdl/FooService.wsdl",
                  targetNamespace = "http://org/example/foo") 
public class Foo_Service extends Service {

    public final static URL WSDL_LOCATION;

    public final static QName SERVICE = new QName("http://org/example/foo", "Foo");
    public final static QName FooSOAPOverHTTP = new QName("http://org/example/foo", "Foo_SOAPOverHTTP");
    static {
        URL url = Foo_Service.class.getClassLoader().getResource("wsdl/FooService.wsdl");
        if (url == null) {
            Java.util.logging.Logger.getLogger(Foo_Service.class.getName())
                .log(Java.util.logging.Level.INFO, 
                     "Can not initialize the default wsdl from {0}", "classpath:wsdl/FooService.wsdl");
        }       
        WSDL_LOCATION = url;
    }

これは、バージョン2.4.1以降のcxf-codegen-pluginでのみ機能することに注意してください。

195
Kyle

を使用しております

wsdlLocation = "WEB-INF/wsdl/WSDL.wsdl"

つまり、クラスパスに関連するパスを使用します。

マーシャリング/アンマーシャリング中のメッセージの検証には、実行時にWSDLが必要になると思います。

20
BPS

org.jvnet.jax-ws-commons:jaxws-maven-pluginを使用して、ビルド時にWSDLからクライアントを生成する場合:

  • WSDLをsrc/main/resourcesのどこかに配置します
  • notwsdlLocationの前にclasspath:を付ける
  • wsdlLocationの前に/を付けてください

例:

  • WSDLは/src/main/resources/foo/bar.wsdlに保存されます
  • jaxws-maven-pluginおよび<wsdlDirectory>${basedir}/src/main/resources/foo</wsdlDirectory>を使用して<wsdlLocation>/foo/bar.wsdl</wsdlLocation>を構成する
13

1)場合によっては、はい。 WSDLにポリシーなど、実行時の動作を指示するものが含まれている場合、実行時にWSDLが必要になる場合があります。ポリシー関連のものなどのアーティファクトは生成されません。また、いくつかのあいまいなRPC /リテラル​​の場合、必要なすべての名前空間が生成されたコードで出力されるわけではありません(仕様ごと)。したがって、それらにはwsdlが必要になります。ただし、あいまいなケース。

2)何かがうまくいくと思った。 CXFのバージョンそれはバグのように聞こえます。そこに空の文字列(スペースのみ)を試すことができます。それが機能するかどうかはわかりません。つまり、コードでは、WSDL URLを取得してnullを渡すコンストラクターを使用できます。 wsdlは使用されません。

3)上記の制限のみ。

9
Daniel Kulp

Wsdl2javaの使用を回避できる可能性はありますか?すぐにCXFフロントエンドAPIを使用して、SOAP Webサービスを呼び出すことができます。唯一の問題は、クライアント側でSEIとVOを作成する必要があることです。サンプルコードを次に示します。

package com.aranin.weblog4j.client;

import com.aranin.weblog4j.services.BookShelfService;
import com.aranin.weblog4j.vo.BookVO;
import org.Apache.cxf.jaxws.JaxWsProxyFactoryBean;

public class DemoClient {
    public static void main(String[] args){
        String serviceUrl = "http://localhost:8080/weblog4jdemo/bookshelfservice";
        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
        factory.setServiceClass(BookShelfService.class);
        factory.setAddress(serviceUrl);
        BookShelfService bookService = (BookShelfService) factory.create();

        //insert book
        BookVO bookVO = new BookVO();
        bookVO.setAuthor("Issac Asimov");
        bookVO.setBookName("Foundation and Earth");

        String result = bookService.insertBook(bookVO);

        System.out.println("result : " + result);

        bookVO = new BookVO();
        bookVO.setAuthor("Issac Asimov");
        bookVO.setBookName("Foundation and Empire");

        result = bookService.insertBook(bookVO);

        System.out.println("result : " + result);

        bookVO = new BookVO();
        bookVO.setAuthor("Arthur C Clarke");
        bookVO.setBookName("Rama Revealed");

        result = bookService.insertBook(bookVO);

        System.out.println("result : " + result);

        //retrieve book

        bookVO = bookService.getBook("Foundation and Earth");

        System.out.println("book name : " + bookVO.getBookName());
        System.out.println("book author : " + bookVO.getAuthor());

    }
}

ここで完全なチュートリアルを見ることができます http://weblog4j.com/2012/05/01/developing-soap-web-service-using-Apache-cxf/

4
Niraj Singh

生成できました

static {
    WSDL_LOCATION = null;
}

wsdlurlにnullを持つようにpomファイルを構成することにより:

    <plugin>
        <groupId>org.Apache.cxf</groupId>
        <artifactId>cxf-codegen-plugin</artifactId>
        <executions>
            <execution>
                <id>generate-sources</id>
                <phase>generate-sources</phase>
                <configuration>
                    <sourceRoot>${basedir}/target/generated/src/main/Java</sourceRoot>
                    <wsdlOptions>
                        <wsdlOption>
                            <wsdl>${basedir}/src/main/resources/service.wsdl</wsdl>
                            <extraargs>
                                <extraarg>-client</extraarg>
                                <extraarg>-wsdlLocation</extraarg>
                                <wsdlurl />
                            </extraargs>
                        </wsdlOption>
                    </wsdlOptions>
                </configuration>
                <goals>
                    <goal>wsdl2Java</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
4
raisercostin

CXF 3.1.7用の更新

私の場合、WSDLファイルをsrc/main/resourcesに配置し、このパスをEclipseのSroucesに追加しました(プロジェクト->ビルドパス->ビルドパスの構成...->ソース[タブ]->フォルダーの追加)。

pomファイルがどのように見えるかを以下に示します。ご覧のとおり、wsdlLocationオプションは必要ありません。

       <plugin>
            <groupId>org.Apache.cxf</groupId>
            <artifactId>cxf-codegen-plugin</artifactId>
            <version>${cxf.version}</version>
            <executions>
                <execution>
                    <id>generate-sources</id>
                    <phase>generate-sources</phase>
                    <configuration>
                        <sourceRoot>${project.build.directory}/generated/cxf</sourceRoot>
                        <wsdlOptions>
                            <wsdlOption>
                                <wsdl>classpath:wsdl/FOO_SERVICE.wsdl</wsdl>
                            </wsdlOption>
                        </wsdlOptions>
                    </configuration>
                    <goals>
                        <goal>wsdl2Java</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

そして、これが生成されたサービスです。ご覧のとおり、URLは絶対ファイルパスからではなく、ClassLoaderから取得されます

@WebServiceClient(name = "EventService", 
              wsdlLocation = "classpath:wsdl/FOO_SERVICE.wsdl",
              targetNamespace = "http://www.sas.com/xml/schema/sas-svcs/rtdm-1.1/wsdl/") 
public class EventService extends Service {

public final static URL WSDL_LOCATION;

public final static QName SERVICE = new QName("http://www.sas.com/xml/schema/sas-svcs/rtdm-1.1/wsdl/", "EventService");
public final static QName EventPort = new QName("http://www.sas.com/xml/schema/sas-svcs/rtdm-1.1/wsdl/", "EventPort");
static {
    URL url = EventService.class.getClassLoader().getResource("wsdl/FOO_SERVICE.wsdl");
    if (url == null) {
        Java.util.logging.Logger.getLogger(EventService.class.getName())
            .log(Java.util.logging.Level.INFO, 
                 "Can not initialize the default wsdl from {0}", "classpath:wsdl/FOO_SERVICE.wsdl");
    }       
    WSDL_LOCATION = url;   
}
4
Mazy

真剣に、トップの答えは私のために働いていません。 cxf.version 2.4.1および3.0.10を試しました。毎回wsdlLocationで絶対パスを生成します。

私の解決策は、wsdl2JavaApache-cxf-3.0.10\bin\コマンドを-wsdlLocation classpath:wsdl/QueryService.wsdlと共に使用することです。

詳細:

    wsdl2Java -encoding utf-8 -p com.jeiao.boss.testQueryService -impl -wsdlLocation classpath:wsdl/testQueryService.wsdl http://127.0.0.1:9999/platf/testQueryService?wsdl
2
jeiao