无法映射 SOAP 服务响应
SOAP service response cannot be mapped
这个问题困扰了我将近两天,我真的需要一些帮助来解决它。
我使用 wsimport 从两个不同的 .wsdl 文件为 Java 项目生成代码。
第一个服务工作得很好,但由于某些原因,无法将来自第二个服务的响应解组为响应对象。
工作服务:
@WebMethod(action = "[actionName]")
@WebResult(name = "getSimpleCompanyInfoResponse", partName = "getSimpleCompanyInfoResponse")
public GetSimpleCompanyInfoResponse getSimpleCompanyInfo(
@WebParam(name = "getSimpleCompanyInfoRequest", partName = "getSimpleCompanyInfoRequest") GetSimpleCompanyInfoRequest getSimpleCompanyInfoRequest);
响应 POJO:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getSimpleCompanyInfoResponse", propOrder = {
//variables
})
public class GetSimpleCompanyInfoResponse {
//variables
}
响应XML:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="[namespaceUri]" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:getSimpleCompanyInfoResponse>
<getSimpleCompanyInfoResponse>
//variables
</getSimpleCompanyInfoResponse>
</ns1:getSimpleCompanyInfoResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
不 工作服务:
@WebMethod(operationName = "PersonnelInfo", action = "[actionName]")
@WebResult(name = "PersonnelInfoResponse", partName = "PersonnelInfoResponse")
public PersonnelInfoResponse personnelInfo(
@WebParam(name = "PersonnelInfoRequest", partName = "PersonnelInfoRequest") PersonnelInfoRequest personnelInfoRequest);
响应 POJO:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "PersonnelInfoResponse", propOrder = {
//variables
})
public class PersonnelInfoResponse {
//variables
}
响应XML:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="[namespaceUri]" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:PersonnelInfoResponse>
//variables
</ns1:PersonnelInfoResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
使用 -Dcom.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=true 或使用 Wireshark 进行监控,我可以看到来自第二个服务的响应信封很好地通过,并且解组不会引发任何异常但最终 PersonnelInfoResponse 为空。
我能看到的唯一区别是 XML 中的第二个服务响应负载缺少外部元素,这似乎是问题所在。但是,我不知道如何 "fix" 它所以它不寻找外部元素。
如果有任何不清楚或遗漏的地方,请告诉我,我会尽力为您提供所有信息。
编辑:
不,不幸的是我无法控制服务本身,我只有 .wsdl 和 .xsd.
我是这样调用服务的:
ReportsControllerPortType port = new ReportsControllerService().getReportsControllerPort();
PersonnelInfoRequest request = new PersonnelInfoRequest();
//fill the required fields in the request, username, password, etc.
PersonnelInfoResponse response = port.personnelInfo(request);
客户端服务存根(ReportsControllerService & ReportsControllerPortType)也是由wsimport根据.wsdl和.xsd.
自动生成的。
编辑 2:
删除操作名称无效,服务初始化失败。以下是 .wsdl-s 中的定义:
工作服务:
<wsdl:message name="getSimpleCompanyInfoRequest">
<wsdl:part name="getSimpleCompanyInfoRequest" type="tns:getSimpleCompanyInfoRequest" />
</wsdl:message>
<wsdl:message name="getSimpleCompanyInfoResponse">
<wsdl:part name="getSimpleCompanyInfoResponse" type="tns:getSimpleCompanyInfoResponse" />
</wsdl:message>
<wsdl:portType name="MonitoringControllerPortType">
<wsdl:operation name="getSimpleCompanyInfo">
<wsdl:input message="tns:getSimpleCompanyInfoRequest" />
<wsdl:output message="tns:getSimpleCompanyInfoResponse" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="MonitoringControllerBinding" type="tns:MonitoringControllerPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="getSimpleCompanyInfo">
<soap:operation soapAction="[domain]/#getSimpleCompanyInfo" style="rpc" />
<wsdl:input>
<soap:body use="literal" namespace="[namespaceUri]" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" namespace="[namespaceUri]" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="MonitoringControllerService">
<wsdl:port name="MonitoringControllerPort" binding="tns:MonitoringControllerBinding">
<soap:address location="[serviceUri]" />
</wsdl:port>
</wsdl:service>
不工作服务:
<wsdl:message name="PersonnelInfoRequest">
<wsdl:part name="PersonnelInfoRequest" type="tns:PersonnelInfoRequest" />
</wsdl:message>
<wsdl:message name="PersonnelInfoResponse">
<wsdl:part name="PersonnelInfoResponse" type="tns:PersonnelInfoResponse" />
</wsdl:message>
<wsdl:portType name="ReportsControllerPortType">
<wsdl:operation name="PersonnelInfo">
<wsdl:input message="tns:PersonnelInfoRequest" />
<wsdl:output message="tns:PersonnelInfoResponse" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ReportsControllerBinding" type="tns:ReportsControllerPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="PersonnelInfo">
<soap:operation soapAction="[domain]/#PersonnelInfo" style="rpc" />
<wsdl:input>
<soap:body use="literal" namespace="[namespaceUri]" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" namespace="[namespaceUri]" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ReportsControllerService">
<wsdl:port name="ReportsControllerPort" binding="tns:ReportsControllerBinding">
<soap:address location="[serviceUri]" />
</wsdl:port>
</wsdl:service>
编辑 3:
ReportsControllerService 和 MonitoringControllerService 扩展 javax.xml.ws.Service 并包含使用的 .wsdl 架构位置和命名空间。如您所见,服务 class returns 一个 PortType 对象:
/**
* This class was generated by the JAX-WS RI. JAX-WS RI 2.2.9-b130926.1035 Generated source version: 2.2
*/
@WebServiceClient(name = "ReportsControllerService", targetNamespace = "[namespaceUri]", wsdlLocation = "[wsdlUri]")
public class ReportsControllerService extends Service {
@WebEndpoint(name = "ReportsControllerPort")
public ReportsControllerPortType getReportsControllerPort() {
return super.getPort(new QName("[namespaceUri]", "ReportsControllerPort"), ReportsControllerPortType.class);
}
}
ReportsControllerPortType 是一个接口,它包含服务中存在的每个操作端点的方法
/**
* This class was generated by the JAX-WS RI. JAX-WS RI 2.2.9-b130926.1035 Generated source version: 2.2
*/
@WebService(name = "ReportsControllerPortType", targetNamespace = "[namespaceUri]")
@SOAPBinding(style = SOAPBinding.Style.RPC)
@XmlSeeAlso({ObjectFactory.class})
public interface ReportsControllerPortType {
@WebMethod(operationName = "PersonnelInfo", action = "[actionName]")
@WebResult(name = "PersonnelInfoResponse", partName = "PersonnelInfoResponse")
public PersonnelInfoResponse personnelInfo(
@WebParam(name = "PersonnelInfoRequest", partName = "PersonnelInfoRequest") PersonnelInfoRequest personnelInfoRequest);
}
}
事实是,所有这些 classes 都是由 JAX-WS 基于 .wsdl 模式自动生成的(正如您从评论中看到的那样)。该实现是在 JDK 内的某个地方抽象出来的,我也无法控制它。是的,我可以重构代码以绕过 JAX-WS,但据我了解,这应该是 事实上 使用基于 .wsdl 的 SOAP 服务的标准方式。
该项目使用 Spring 作为基础框架,我已经确认当我使用 Spring-WS 时这两种服务都可以工作,所以我可以重构,但我想了解为什么这样不工作。
您的 2 个调用之间有一个明显的区别:
你应该尝试从你的第二个调用中删除 operationName = "PersonnelInfo"
,它不存在于第一个工作的调用中。
我相信我可能已经发现您的网络服务运行异常的原因。根据规范,RPC
web 服务必须在其 soap 绑定中满足以下条件(即您那里的 @SOAPBinding
注释)
A style
of RPC
: 检查
LITERAL
的 use
:检查
A parameterStyle
of WRAPPED
: 从你给出的描述来看,WRAPPED
似乎不是这种情况,你看'重新收到没有任何包装的裸 PersonnelInfoResponse
(并可能发送裸 PersonnelInfoRequest
)表明服务本身已损坏。
Use of RPC
style requires the use of WRAPPED
parameter style. Deviations from this is an error
这个问题困扰了我将近两天,我真的需要一些帮助来解决它。
我使用 wsimport 从两个不同的 .wsdl 文件为 Java 项目生成代码。
第一个服务工作得很好,但由于某些原因,无法将来自第二个服务的响应解组为响应对象。
工作服务:
@WebMethod(action = "[actionName]")
@WebResult(name = "getSimpleCompanyInfoResponse", partName = "getSimpleCompanyInfoResponse")
public GetSimpleCompanyInfoResponse getSimpleCompanyInfo(
@WebParam(name = "getSimpleCompanyInfoRequest", partName = "getSimpleCompanyInfoRequest") GetSimpleCompanyInfoRequest getSimpleCompanyInfoRequest);
响应 POJO:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getSimpleCompanyInfoResponse", propOrder = {
//variables
})
public class GetSimpleCompanyInfoResponse {
//variables
}
响应XML:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="[namespaceUri]" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:getSimpleCompanyInfoResponse>
<getSimpleCompanyInfoResponse>
//variables
</getSimpleCompanyInfoResponse>
</ns1:getSimpleCompanyInfoResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
不 工作服务:
@WebMethod(operationName = "PersonnelInfo", action = "[actionName]")
@WebResult(name = "PersonnelInfoResponse", partName = "PersonnelInfoResponse")
public PersonnelInfoResponse personnelInfo(
@WebParam(name = "PersonnelInfoRequest", partName = "PersonnelInfoRequest") PersonnelInfoRequest personnelInfoRequest);
响应 POJO:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "PersonnelInfoResponse", propOrder = {
//variables
})
public class PersonnelInfoResponse {
//variables
}
响应XML:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="[namespaceUri]" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:PersonnelInfoResponse>
//variables
</ns1:PersonnelInfoResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
使用 -Dcom.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump=true 或使用 Wireshark 进行监控,我可以看到来自第二个服务的响应信封很好地通过,并且解组不会引发任何异常但最终 PersonnelInfoResponse 为空。
我能看到的唯一区别是 XML 中的第二个服务响应负载缺少外部元素,这似乎是问题所在。但是,我不知道如何 "fix" 它所以它不寻找外部元素。
如果有任何不清楚或遗漏的地方,请告诉我,我会尽力为您提供所有信息。
编辑:
不,不幸的是我无法控制服务本身,我只有 .wsdl 和 .xsd.
我是这样调用服务的:
ReportsControllerPortType port = new ReportsControllerService().getReportsControllerPort();
PersonnelInfoRequest request = new PersonnelInfoRequest();
//fill the required fields in the request, username, password, etc.
PersonnelInfoResponse response = port.personnelInfo(request);
客户端服务存根(ReportsControllerService & ReportsControllerPortType)也是由wsimport根据.wsdl和.xsd.
自动生成的。编辑 2:
删除操作名称无效,服务初始化失败。以下是 .wsdl-s 中的定义:
工作服务:
<wsdl:message name="getSimpleCompanyInfoRequest">
<wsdl:part name="getSimpleCompanyInfoRequest" type="tns:getSimpleCompanyInfoRequest" />
</wsdl:message>
<wsdl:message name="getSimpleCompanyInfoResponse">
<wsdl:part name="getSimpleCompanyInfoResponse" type="tns:getSimpleCompanyInfoResponse" />
</wsdl:message>
<wsdl:portType name="MonitoringControllerPortType">
<wsdl:operation name="getSimpleCompanyInfo">
<wsdl:input message="tns:getSimpleCompanyInfoRequest" />
<wsdl:output message="tns:getSimpleCompanyInfoResponse" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="MonitoringControllerBinding" type="tns:MonitoringControllerPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="getSimpleCompanyInfo">
<soap:operation soapAction="[domain]/#getSimpleCompanyInfo" style="rpc" />
<wsdl:input>
<soap:body use="literal" namespace="[namespaceUri]" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" namespace="[namespaceUri]" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="MonitoringControllerService">
<wsdl:port name="MonitoringControllerPort" binding="tns:MonitoringControllerBinding">
<soap:address location="[serviceUri]" />
</wsdl:port>
</wsdl:service>
不工作服务:
<wsdl:message name="PersonnelInfoRequest">
<wsdl:part name="PersonnelInfoRequest" type="tns:PersonnelInfoRequest" />
</wsdl:message>
<wsdl:message name="PersonnelInfoResponse">
<wsdl:part name="PersonnelInfoResponse" type="tns:PersonnelInfoResponse" />
</wsdl:message>
<wsdl:portType name="ReportsControllerPortType">
<wsdl:operation name="PersonnelInfo">
<wsdl:input message="tns:PersonnelInfoRequest" />
<wsdl:output message="tns:PersonnelInfoResponse" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ReportsControllerBinding" type="tns:ReportsControllerPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="PersonnelInfo">
<soap:operation soapAction="[domain]/#PersonnelInfo" style="rpc" />
<wsdl:input>
<soap:body use="literal" namespace="[namespaceUri]" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" namespace="[namespaceUri]" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ReportsControllerService">
<wsdl:port name="ReportsControllerPort" binding="tns:ReportsControllerBinding">
<soap:address location="[serviceUri]" />
</wsdl:port>
</wsdl:service>
编辑 3:
ReportsControllerService 和 MonitoringControllerService 扩展 javax.xml.ws.Service 并包含使用的 .wsdl 架构位置和命名空间。如您所见,服务 class returns 一个 PortType 对象:
/**
* This class was generated by the JAX-WS RI. JAX-WS RI 2.2.9-b130926.1035 Generated source version: 2.2
*/
@WebServiceClient(name = "ReportsControllerService", targetNamespace = "[namespaceUri]", wsdlLocation = "[wsdlUri]")
public class ReportsControllerService extends Service {
@WebEndpoint(name = "ReportsControllerPort")
public ReportsControllerPortType getReportsControllerPort() {
return super.getPort(new QName("[namespaceUri]", "ReportsControllerPort"), ReportsControllerPortType.class);
}
}
ReportsControllerPortType 是一个接口,它包含服务中存在的每个操作端点的方法
/**
* This class was generated by the JAX-WS RI. JAX-WS RI 2.2.9-b130926.1035 Generated source version: 2.2
*/
@WebService(name = "ReportsControllerPortType", targetNamespace = "[namespaceUri]")
@SOAPBinding(style = SOAPBinding.Style.RPC)
@XmlSeeAlso({ObjectFactory.class})
public interface ReportsControllerPortType {
@WebMethod(operationName = "PersonnelInfo", action = "[actionName]")
@WebResult(name = "PersonnelInfoResponse", partName = "PersonnelInfoResponse")
public PersonnelInfoResponse personnelInfo(
@WebParam(name = "PersonnelInfoRequest", partName = "PersonnelInfoRequest") PersonnelInfoRequest personnelInfoRequest);
}
}
事实是,所有这些 classes 都是由 JAX-WS 基于 .wsdl 模式自动生成的(正如您从评论中看到的那样)。该实现是在 JDK 内的某个地方抽象出来的,我也无法控制它。是的,我可以重构代码以绕过 JAX-WS,但据我了解,这应该是 事实上 使用基于 .wsdl 的 SOAP 服务的标准方式。
该项目使用 Spring 作为基础框架,我已经确认当我使用 Spring-WS 时这两种服务都可以工作,所以我可以重构,但我想了解为什么这样不工作。
您的 2 个调用之间有一个明显的区别:
你应该尝试从你的第二个调用中删除 operationName = "PersonnelInfo"
,它不存在于第一个工作的调用中。
我相信我可能已经发现您的网络服务运行异常的原因。根据规范,RPC
web 服务必须在其 soap 绑定中满足以下条件(即您那里的 @SOAPBinding
注释)
A
style
ofRPC
: 检查LITERAL
的use
:检查A
parameterStyle
ofWRAPPED
: 从你给出的描述来看,WRAPPED
似乎不是这种情况,你看'重新收到没有任何包装的裸PersonnelInfoResponse
(并可能发送裸PersonnelInfoRequest
)表明服务本身已损坏。
Use of
RPC
style requires the use ofWRAPPED
parameter style. Deviations from this is an error