【问题标题】:JAX-WS Client won't accept blank namespace in SOAP ResponseJAX-WS 客户端不接受 SOAP 响应中的空白命名空间
【发布时间】:2016-04-21 16:18:10
【问题描述】:

我正在尝试使用 JAX-WS 和 wsimport 生成的代码从 Web 服务中提取数据。我能够发送请求并从服务器获取响应,但是 JAX-WS 在尝试读取响应时会引发异常,因为响应正文中的任何元素都没有声明的命名空间。

Exception in thread "main" com.sun.xml.internal.ws.streaming.XMLStreamReaderException: unexpected XML tag. expected: {http://www.theserver.com/cmdb_rel_ci}getRecordsResponse but found: {null}getRecordsResponse

WSDL 摘录:

<wsdl:definitions xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:tns="http://www.theserver.com/cmdb_rel_ci" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:sncns="http://www.theserver.com" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" targetNamespace="http://www.theserver.com">
  <wsdl:types>
    <xsd:schema elementFormDefault="unqualified" targetNamespace="http://www.theserver.com/cmdb_rel_ci">
      <xsd:element name="getRecords">
        <xsd:complexType>
          <xsd:sequence>
            <!-- Request arguments -->
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
      <xsd:element name="getRecordsResponse">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element maxOccurs="unbounded" minOccurs="0" name="getRecordsResult">
              <xsd:complexType>
                <xsd:sequence>
                  <!-- Response Fields -->
                </xsd:sequence>
              </xsd:complexType>
            </xsd:element>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>
  </wsdl:types>
  <wsdl:message name="getRecordsSoapIn">
    <wsdl:part name="cmdb_rel_ci" element="tns:getRecords"></wsdl:part>
  </wsdl:message>
  <wsdl:message name="getRecordsSoapOut">
    <wsdl:part name="cmdb_rel_ci" element="tns:getRecordsResponse"></wsdl:part>
  </wsdl:message>
</wsdl:definitions>

SoapUI 中的成功请求和响应:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns2="http://www.theserver.com/cmdb_rel_ci">
  <soapenv:Header/>
  <soapenv:Body>
    <ns2:getRecords>
      <arg1>value</arg1>
      <!-- Remaining Arguments -->
    </ns2:getRecords>
  </soapenv:Body>
</soapenv:Envelope>


<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <SOAP-ENV:Body>
    <getRecordsResponse>
      <getRecordsResult>
        <resultField1>value</resultField1>
        <resultField2>value2</resultField2>
        <!-- etc. -->
      </getRecordsResult>
      <!-- Other getRecordsResult elements -->
    </getRecordsResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

我如何告诉 JAX-WS &lt;getRecordsResponse&gt; 元素没有命名空间?我已经尝试在@ResponseWrapper 注释中为getRecords() 设置targetNamespace = "",但这只是让它期望来自@WebService 的targetNamespace 参数。当我尝试将 WebService 的目标命名空间设置为空白时,它试图从 Java 包名称中推断出命名空间(例如“http://my_package.com”)。

【问题讨论】:

    标签: java soap jax-ws


    【解决方案1】:

    我无法找到告诉 JAX-WS 不要期望命名空间的方法,但我能够通过在 SOAPHandler 中预处理响应并手动将命名空间添加到 XML 元素(通过给出它是一个包含命名空间声明的新 QName。

    MyHandler.java:

    public class MyHandler implements SOAPHandler<SOAPMessageContext> {
        @Override
        public void close(MessageContext context) { 
        }
    
        @Override
        public boolean handleMessage(SOAPMessageContext context) {
            //Don't intercept outbound messages (SOAP Requests)
            if ((Boolean)context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)) {return true;}
    
            SOAPMessage message = context.getMessage();
            try {
                SOAPBody body = message.getSOAPBody();
                Iterator<SOAPElement> bodyIterator = body.getChildElements();
                SOAPElement responseElement = bodyIterator.next();
                responseElement.setElementQName(new QName("http://www.theserver.com/cmdb_rel_ci", origGetRecordsResponse.getLocalName(), "cmdb"));
            } catch (Exception e) {e.printStackTrace();}
            return true;
        }
    
        @Override
        public boolean handleFault(SOAPMessageContext context) {
            return false;
        }
    
        @Override
        public Set<QName> getHeaders() {
            return Collections.emptySet();
        }
    }
    

    然后我只需要在我的主类中使用以下代码将我的 Handler 添加到 HandlerChain,它就可以工作了。

    Binding binding = ((BindingProvider)port).getBinding();
    List<Handler> handlers = binding.getHandlerChain();
    handlers.add(new MyHandler());
    binding.setHandlerChain(handlers);
    

    【讨论】:

      【解决方案2】:

      这里的问题是 如何告诉 JAX-WS 该元素没有命名空间?我已经尝试在 getRecords() 的 @ResponseWrapper 注释中设置 targetNamespace = "" ,但这只是让它期望来自 @WebService 的 targetNamespace 参数。

      答案在这里 https://docs.oracle.com/cd/E13222_01/wls/docs92/webserv/annotations.html

      要确保不会忽略 targetNamespace,请将 SOAPBinding 样式更改为 SOAPBinding.Style.Document

      来自上述 url 的信息提供了对该问题的更多见解。

      返回值的 XML 命名空间。此值仅用于文档样式的 Web 服务,其中返回值映射到 XML 元素。 默认值为 Web 服务的 targetNamespace。

      【讨论】:

      • 我的客户端是由wsdl生成的,即文档样式,如何更改?
      • 您可以更改为接口方法生成的存根中的注释@SOAPBinding(style=Style.DOCUMENT)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-04
      • 1970-01-01
      • 2015-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多