更新:我已经能够缩小范围了. wsdl在自己的命名空间中定义了对象,比如http://www.acme.com/ws.我从服务中得到的回应是
<?xml version="1.0" encoding="UTF-8"?> ... SOAP envelope ... <ns1:opINFOWLResponse xmlns:ns1="http://www.acme.com/ws" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <ns1:responseINFOWL xsi:type="ns1:responseINFOWL"> <result>6003</result> <ndserr/> <transid>61437594</transid> <descriptionerr>BLAH.</descriptionerr> </ns1:responseINFOWL> </ns1:opINFOWLResponse> ... SOAP closing tags ...
并且被解组为非null的OpINFOWLResponse,它包装一个非null的responseINFOWL对象,所有字段都设置为null.为了好玩,我尝试编写几行来解组上面的代码片段(在剥离SOAP开销之后)
JAXBContext ctx = JAXBContext.newInstance(OpINFOWLResponse.class); Unmarshaller u = ctx.createUnmarshaller(); OpINFOWLResponse o = (OpINFOWLResponse) u.unmarshal(new StringReader(theSnippetAbove)); ResponseINFOWL w = o.getResponseINFOWL();
我得到了相同的结果.如果我将上面的XML更改为
<?xml version="1.0" encoding="UTF-8"?> <ns1:opINFOWLResponse xmlns:ns1="http://www.acme.com/ws" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <ns1:responseINFOWL xsi:type="ns1:responseINFOWL"> <ns1:result>6003</ns1:result> <ns1:ndserr/> <ns1:transid>61437594</ns1:transid> <ns1:descriptionerr>BLAH.</ns1:descriptionerr> </ns1:responseINFOWL> </ns1:opINFOWLResponse>
一切正常.游民.
更新(再次):与jaxb-RI和Moxy相同的行为.还是不知道出了什么问题.
更新(9月9日):下面关于命名空间限定错误的建议很有意思,但我认为wsimport会把事情做对.无论如何,这是我的package-info.java
@XmlSchema( namespace = "http://www.acme.com/ws",elementFormDefault = XmlNsForm.QUALIFIED) package it.sky.guidaTv.service.remote; import javax.xml.bind.annotation.XmlSchema; import javax.xml.bind.annotation.XmlNsForm;
这是ResponseINFOWL类的相关部分
/* * <p>Java class for responseINFOWL complex type. * * <p>The following schema fragment specifies the expected content contained within this class. * * <pre> * <complexType name="responseINFOWL"> * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <sequence> * <element name="result" type="{http://www.w3.org/2001/XMLSchema}string"/> * <element name="descriptionerr" type="{http://www.w3.org/2001/XMLSchema}string"/> * <element name="transid" type="{http://www.w3.org/2001/XMLSchema}string"/> * <element name="ndserr" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> * <element name="wallet" type="{http://www.acme.com/ws}t_wallet" minOccurs="0"/> * </sequence> * </restriction> * </complexContent> * </complexType> * </pre> * * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "responseINFOWL",propOrder = { "result","descriptionerr","transid","ndserr","wallet" }) public class ResponseINFOWL { @XmlElement(required = true) protected String result; @XmlElement(required = true) protected String descriptionerr; @XmlElement(required = true) protected String transid; protected String ndserr; protected TWallet wallet; // getters,setters and all. }
我已尝试在package-info中使用命名空间,但仍然没有乐趣.
解决方法
特别是,实际响应主体内容上的命名空间不是JAX-WS的wsimport实用程序生成的客户端代码所期望的.例如,实际响应看起来像这样,serviceResponse及其所有子节点都在命名空间“http://foo.com”中:
<?xml version="1.0" encoding="utf-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <serviceResponse xmlns="http://foo.com"> <messageReturn> <messageId>12345</messageId> <status>Ok</status> </messageReturn> </serviceResponse> </soapenv:Body> </soapenv:Envelope>
与实际返回的内容相反,wsimport生成的客户端存根期望类似下面的响应,命名空间“http://foo.com”中的serviceResponse元素和匿名命名空间中包含的子messageReturn元素.
<?xml version="1.0" encoding="utf-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <n1:serviceResponse xmlns:n1="http://foo.com"> <messageReturn> <messageId>12345</messageId> <status>Ok</status> </messageReturn> </n1:serviceResponse> </soapenv:Body> </soapenv:Envelope>
由于我无法更改我正在使用的服务,我自己编写了一个新的WSDL,它使用包装的doc-literal绑定来显式控制响应的预期结构(当然还有请求).在IBM Developerworks.上有一篇关于WSDL绑定类型的非常好的文章
我创建的WSDL看起来像这样:
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://foo.com" xmlns:tns="http://foo.com" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- Define the XML types we need to send and receive (used by the message definitions below) --> <wsdl:types> <schema targetNamespace="http://foo.com" xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <!-- Reusable types --> <complexType name="ResponseType"> <sequence> <element name="messageId" nillable="true" type="xsd:string" /> <element name="status" nillable="true" type="xsd:string" /> </sequence> </complexType> <complexType name="InputType"> <sequence> <element name="firstName" nillable="true" type="xsd:string" /> <element name="lastName" nillable="true" type="xsd:string" /> <element name="command" nillable="true" type="xsd:string" /> </sequence> </complexType> <!-- Specific input/output elements used in wsdl:message definitions --> <element name="serviceResponse"> <complexType> <sequence> <element name="messageReturn" type="tns:ResponseType" /> </sequence> </complexType> </element> <element name="serviceRequest"> <complexType> <sequence> <element name="message" type="tns:InputType" /> </sequence> </complexType> </element> </schema> </wsdl:types> <!-- Define the WSDL messages we send/receive (used by the port definition below) --> <wsdl:message name="serviceResponseMessage"> <wsdl:part name="part1Name" element="tns:serviceResponse" /> </wsdl:message> <wsdl:message name="serviceRequestMessage"> <wsdl:part name="part1name" element="tns:serviceRequest" /> </wsdl:message> <!-- Define the WSDL port (used by the binding definition below) --> <wsdl:portType name="ServicePort"> <wsdl:operation name="serviceOperation"> <wsdl:input message="tns:serviceRequestMessage" /> <wsdl:output message="tns:serviceResponseMessage" /> </wsdl:operation> </wsdl:portType> <!-- Define the WSDL binding of the port (used by the service definition below) --> <wsdl:binding name="ServiceSoapBinding" type="tns:ServicePort"> <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="serviceOperation"> <wsdlsoap:operation soapAction="" /> <wsdl:input> <wsdlsoap:body use="literal" /> </wsdl:input> <wsdl:output> <wsdlsoap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <!-- Finally,define the actual WSDL service! --> <wsdl:service name="UserCommandService"> <wsdl:port binding="tns:ServiceSoapBinding" name="ServicePort"> <!-- This address is just a placeholder,since the actual target URL will be specified at runtime --> <wsdlsoap:address location="http://localhost:8080/blah" /> </wsdl:port> </wsdl:service> </wsdl:definitions>
使用自定义WSDL,我能够使用wsimport生成与服务完美配合的客户端存根.同样,使用包装的doc-literal方法,我完全控制了请求/响应的预期结构和命名空间,因此如果需要,我可以在该XML中实现多个命名空间.
请享用…