java - 如何避免需要在 CXF 或 JAX-WS 生成的 Web 服务客户端中指定 WSDL 位置?

标签 java wsdl cxf wsdl2java

当我通过 maven 使用 CXF 中的 wsdl2java(生成类似于 wsimport 的内容)生成 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,因此我们尝试包含 <wsdlLocation></wsdlLocation>在 CXF 的配置中尝试强制源生成器将 wsdlLocation 留空。但是,这只是让它忽略 XML 标记,因为它是空的。我们使用 <wsdlLocation>" + "</wsdlLocation> 做了一个非常丑陋可耻的 hack。 .

这也改变了其他地方:

@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. 我们可以用那个 hack 得到什么不好的副作用?我们仍然无法对其进行测试以了解会发生什么,所以如果有人可以提前说,那就太好了。

最佳答案

我今天终于想出了这个问题的正确答案。

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

关于java - 如何避免需要在 CXF 或 JAX-WS 生成的 Web 服务客户端中指定 WSDL 位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4455195/

相关文章:

.net - 使用 SOAP Web 服务,反序列化值类型时出错

jaxb - CXF JAXB 数据绑定(bind)问题 - java.io.Serialized 是一个接口(interface),而 JAXB 无法处理接口(interface)

java - JAX-WS 响应消息中的可选部分

java - java中点击菜单项时如何改变形状

java - 为什么Java 6重写SortedMap中的keySet()、entrySet()和values()接口(interface)

java - 定位 .jar 文件中的内部目录 -- java

java - 使用带有Java11的Maven插件从WSDL文件生成JAX-WS类

java - Spring MVC helloworld - 包名称不能以java开头?

Java泛型和反射: class loading

tomcat - tomee ExceptionInInitializerError 和 ThreadLocalProxy 在类加载器中不可见