JAX-WS 客户端不接受 SOAP 响应中的空白命名空间
JAX-WS Client won't accept blank namespace in SOAP Response
我正在尝试使用 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 <getRecordsResponse>
元素没有命名空间?我已经尝试在 @ResponseWrapper
注释中为 getRecords()
设置 targetNamespace = ""
,但这只会让它期望来自 @WebService
的 targetNamespace 参数。当我尝试将 WebService 的目标命名空间设置为空白时,它试图从 Java 包名称(例如“http://my_package.com”)中推断出一个命名空间。
我无法找到告诉 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();
}
}
然后我只需要在我的主 class 中使用以下代码将我的 Handler 添加到 HandlerChain,它就成功了。
Binding binding = ((BindingProvider)port).getBinding();
List<Handler> handlers = binding.getHandlerChain();
handlers.add(new MyHandler());
binding.setHandlerChain(handlers);
这里的问题是
我如何告诉 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 中的信息可以让您更深入地了解问题。
return 值的 XML 命名空间。此值仅用于文档样式的 Web 服务,其中 return 值映射到 XML 元素。
默认值为 Web 服务的 targetNamespace。
我正在尝试使用 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 <getRecordsResponse>
元素没有命名空间?我已经尝试在 @ResponseWrapper
注释中为 getRecords()
设置 targetNamespace = ""
,但这只会让它期望来自 @WebService
的 targetNamespace 参数。当我尝试将 WebService 的目标命名空间设置为空白时,它试图从 Java 包名称(例如“http://my_package.com”)中推断出一个命名空间。
我无法找到告诉 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();
}
}
然后我只需要在我的主 class 中使用以下代码将我的 Handler 添加到 HandlerChain,它就成功了。
Binding binding = ((BindingProvider)port).getBinding();
List<Handler> handlers = binding.getHandlerChain();
handlers.add(new MyHandler());
binding.setHandlerChain(handlers);
这里的问题是 我如何告诉 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 中的信息可以让您更深入地了解问题。
return 值的 XML 命名空间。此值仅用于文档样式的 Web 服务,其中 return 值映射到 XML 元素。 默认值为 Web 服务的 targetNamespace。