java 使用 Apache CXF 的 Web 服务上的命名空间问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16524372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 23:12:48  来源:igfitidea点击:

namespace issue on web service with Apache CXF

javaweb-servicescxfjaxb2java-ws

提问by Aaron T

I'm using Apache CXF 2.7.3, and running into a namespace issue that I really don't understand. I've tried extensively to search on this, but most of the results that I find are for different behaviors. The issue is when invoking the web service, it will fail if the parameter element is namespace qualified. All the rest of the elements in the message are qualified, and it accepts that, just not the parameter element. Here is the precise behavior:

我正在使用 Apache CXF 2.7.3,但遇到了一个我真的不明白的命名空间问题。我已经广泛尝试对此进行搜索,但我发现的大多数结果都是针对不同行为的。问题是在调用 Web 服务时,如果参数元素是命名空间限定的,它将失败。消息中的所有其余元素都是合格的,它接受这一点,但不是参数元素。这是确切的行为:

request WITHOUTparameter element qualified:

没有参数元素限定的请求:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:ord="http://www.example.org/order">
<soapenv:Header/>
   <soapenv:Body>
      <ord:getOrder>
         <id>a</id>
      </ord:getOrder>
   </soapenv:Body>
</soapenv:Envelope>

results in success:

结果成功:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns2:getOrderResponse xmlns:ns2="http://www.example.org/order">
         <return>
            <ns2:errorCode/>
            <ns2:errorMessage/>
            <ns2:order>
               <ns2:orderNumber>ABC123</ns2:orderNumber>
               <ns2:lastName>Smith</ns2:lastName>
            </ns2:order>
         </return>
      </ns2:getOrderResponse>
   </soap:Body>
</soap:Envelope>

request WITHparameter qualified:

请求WITH参数限定:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:ord="http://www.example.org/order">
   <soapenv:Header/>
   <soapenv:Body>
      <ord:getOrder>
         <ord:id>a</ord:id>
      </ord:getOrder>
   </soapenv:Body>
</soapenv:Envelope>

results in exception from JAXB:

导致 JAXB 异常:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <soap:Fault>
         <faultcode>soap:Client</faultcode>
         <faultstring>Unmarshalling Error: unexpected element (uri:"http://www.example.org/order", local:"id"). Expected elements are &lt;{}id></faultstring>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

In all the research I have done, this usually means that a namespace doesn't match up somewhere. But I have checked it thoroughly, and the namespace is identical everywhere, including the ObjectFactory.class, package-info.class, and the cxf-servlet.xml configuration file as well as the @WebService annotation. Can anyone point me in the right direction as to what I am missing here?

在我所做的所有研究中,这通常意味着命名空间在某处不匹配。但是我已经彻底检查过了,命名空间到处都是相同的,包括ObjectFactory.class、package-info.class和cxf-servlet.xml配置文件以及@WebService注解。任何人都可以指出我在这里缺少什么的正确方向吗?

回答by Aaron T

The source of the problem is wsgen, and I think this is a bug. It does not make the wsdl and the jaxb generated classes compatible. In the jaxb generated classes, the elements are not default form qualified, which puts the parameter element into a null namespace. However in the WSDL, it ISdefault form qualified, and therein lies the problem. There are probably a number of ways to solve this, the most quick and dirty way I found is to set the targetNamespace on the @WebParam annotation. Here are code snippets to demonstrate what I mean, and I hope this helps someone else who runs into this.

问题的根源是wsgen,我认为这是一个错误。它不会使 wsdl 和 jaxb 生成的类兼容。在 jaxb 生成的类中,元素不是默认表单限定的,这将参数元素放入空命名空间。然而,在 WSDL 中,它默认表单限定的,这就是问题所在。可能有很多方法可以解决这个问题,我发现的最快速和最肮脏的方法是在 @WebParam 注释上设置 targetNamespace。下面是代码片段来演示我的意思,我希望这可以帮助遇到这个问题的其他人。

Here is what I had originally for the bottom-up implementation class:

这是我最初为自下而上的实现类所做的:

@WebService(serviceName="OrderService")
public class OrderService {

    public OrderResponse getOrder(@WebParam(name="id", targetNamespace="http://www.example.org/order") String id)  {

This will result in the following generated JAXB classes. As you can see it sets the namespace for the root but its not form qualified, and it does not generate a package-info file either.

这将产生以下生成的 JAXB 类。正如您所看到的,它为根设置了命名空间,但它的形式没有限定,并且它也不会生成包信息文件。

@XmlRootElement(name = "getOrder", namespace = "http://www.example.org/order")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getOrder", namespace = "http://www.example.org/order")

public class GetOrder {

    @XmlElement(name = "id")
    private java.lang.String id;

Then I changed the service implementation class, to add the namespace to the @WebParam:

然后我更改了服务实现类,将命名空间添加到@WebParam:

@WebService(serviceName="OrderService", targetNamespace="http://www.example.org/order")
public class OrderService {

    public OrderResponse getOrder(@WebParam(name="id", targetNamespace="http://www.example.org/order") String id)  {

While that doesn't make it default form qualified, it does add the namespace to the element in the generated JAXB class:

虽然这不会使它成为默认表单限定,但它确实将命名空间添加到生成的 JAXB 类中的元素:

@XmlRootElement(name = "getOrder", namespace = "http://www.example.org/order")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getOrder", namespace = "http://www.example.org/order")

public class GetOrder {

    @XmlElement(name = "id", namespace = "http://www.example.org/order")
    private java.lang.String id;