1. ホーム
  2. java

[解決済み] CXFまたはJAX-WSで生成されたWebサービスクライアントで、WSDLの場所を指定する必要がないようにするにはどうすればよいですか。

2022-04-21 14:11:32

質問内容

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

@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ファイルのどこかに置き、それをクラスパスすることです。しかし、私たちはこれを避けたい。CXFとJAXBはWSDLとXSDに基づいてすべてのものを生成しているので、実行時にWSDLを知る必要はないと考えているのだ。

wsdlLocation属性はWSDLの場所を上書きするためのもので、(少なくとも私はどこかで読んだのですが)そのデフォルト値は""です。maven を使用しているため、WSDL を記述するために <wsdlLocation></wsdlLocation> CXFの設定内で、ソース・ジェネレーターがwsdlLocationを空白にするように強制しようとします。しかし、これは単に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. そのハックによって、どんな悪い副作用があるのでしょうか?私たちはまだそれがどうなるかテストすることができないので、誰かが事前に言ってくれると助かるのですが。

解決方法は?

今日、ようやくこの問題の正解がわかりました。

<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>

の値に接頭辞をつけていることに注目してください。 wsdlLocationclasspath: . これはプラグインに、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 でしか動作しないことに注意してください。