java 我的 jax-ws 网络服务客户端只返回空对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7174346/
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-30 18:56:58  来源:igfitidea点击:

My jax-ws webservice client returns only empty objects

javajaxbjax-wsmoxy

提问by agnul

I have a third party webservice for which I generate a client using wsimport. Each call to the webservice completes successfully, but the response object I get back has all its fields set to null. Monitoring the network I can see that on the wire all of the XML elements in the response message have values in them, so the object should have non-null data in it. Also, a client for the same service generated with old axis1 and called with the same data returns a non-empty response. Any idea what's happening? (In case it makes any difference I'm using MOXy's implementation of JAXB).

我有一个第三方网络服务,我使用 wsimport 为其生成一个客户端。对 web 服务的每次调用都成功完成,但我返回的响应对象的所有字段都设置为 null。监控网络我可以看到,在网络上,响应消息中的所有 XML 元素都包含值,因此对象中应该包含非空数据。此外,使用旧轴 1 生成并使用相同数据调用的相同服务的客户端返回非空响应。知道发生了什么吗?(如果它有任何不同,我正在使用 MOXy 的 JAXB 实现)。

Update: I've been able to narrow it down. The wsdl defines object in its own namespace, say http://www.acme.com/ws. The response I get from the service is

更新:我已经能够缩小范围。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 ...

and is unmarshalled to a non null OpINFOWLResponsewhich wraps around a non null responseINFOWLobject with all the fields set to null. Just for fun I've tried writing a couple of lines to unmarshal the above snippet (after stripping the SOAP overhead)

并被解组为一个非空值OpINFOWLResponse,该非空值环绕一个非空responseINFOWL对象,所有字段都设置为空。只是为了好玩,我尝试写几行来解​​组上面的代码片段(在去除 SOAP 开销之后)

JAXBContext ctx = JAXBContext.newInstance(OpINFOWLResponse.class);
Unmarshaller u = ctx.createUnmarshaller();

OpINFOWLResponse o = (OpINFOWLResponse) u.unmarshal(new StringReader(theSnippetAbove));
ResponseINFOWL w = o.getResponseINFOWL();

and I get the same result. If I change the XML above to

我得到了相同的结果。如果我将上面的 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>

Everything works fine. Bummer.

一切正常。无赖。

Update (again): Same behaviour with both jaxb-RI and Moxy. Still have no idea what's wrong.

更新(再次):jaxb-RI 和 Moxy 的行为相同。仍然不知道出了什么问题。

Update (Sep. 9): The suggestion below about namespace qualification being wrong is interesting, but I supposed wsimport would get things right. Anyway, this is my package-info.java

更新(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;

and this is the relevant part of the ResponseINFOWLclass

这是ResponseINFOWL课程的相关部分

/*
 * <p>Java class for responseINFOWL complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType name="responseINFOWL">
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="result" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *         &lt;element name="descriptionerr" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *         &lt;element name="transid" type="{http://www.w3.org/2001/XMLSchema}string"/>
 *         &lt;element name="ndserr" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
 *         &lt;element name="wallet" type="{http://www.acme.com/ws}t_wallet" minOccurs="0"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/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.

}

I've tried playing a bit with the namespaces in package-infobut still no joy.

我试过玩一些命名空间,package-info但仍然没有快乐。

回答by Roy Wood

I recently ran into the exact same problem you encountered, and it came down to the fact that the service I was contacting was returning something different from what its WSDL advertised. The service used an old version of Apache Axis (1.4) with behaviour that conflicts with current JAX-WS implementations.

我最近遇到了与您遇到的完全相同的问题,归根结底是我正在联系的服务返回的内容与其 WSDL 宣传的内容不同。该服务使用旧版本的 Apache Axis (1.4),其行为与当前的 JAX-WS 实现相冲突。

In particular, the namespace on the actual response body contents was NOT what was expected by the client code generated by JAX-WS's wsimport utility. For example, the actual response looked something like this, with the serviceResponse and all its children in namespace "http://foo.com":

特别是,实际响应正文内容上的命名空间不是 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>

In contrast to what was actually coming back, the client stubs generated by wsimport were expecting something like the response below, with the serviceResponse element in namespace "http://foo.com" and the contained child messageReturn element in the anonymous namespace.

与实际返回的内容相反,由 wsimport 生成的客户端存根期待类似下面的响应,其中 serviceResponse 元素位于命名空间“ http://foo.com”中,包含的子 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>

Since I could not change the service I was consuming, I instead wrote a new WSDL myself that used a wrapped doc-literal binding to explicitly control the expected structure of the response (and request, of course). There is a really good article on WSDL binding types over IBM Developerworks.

由于我无法更改我正在使用的服务,因此我自己编写了一个新的 WSDL,它使用包装的 doc-literal 绑定来显式控制响应(当然还有请求)的预期结构。IBM Developerworks上有一篇关于 WSDL 绑定类型的非常好的文章

The WSDL I created looked something like this:

我创建的 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>

With the custom WSDL, I was able to use wsimport to generate client stubs that work perfectly with the service. As well, with the wrapped doc-literal approach, I completely control the expected structure and namespace of the request/response, so I can implement multiple namespaces in that XML if necessary.

使用自定义 WSDL,我能够使用 wsimport 生成与服务完美配合的客户端存根。同样,使用包装的 doc-literal 方法,我可以完全控制请求/响应的预期结构和命名空间,因此如有必要,我可以在该 XML 中实现多个命名空间。

Enjoy...

享受...

回答by bdoughan

Please correct me if I have your use case incorrect.

如果我的用例不正确,请纠正我。

You can unmarshal:

您可以解组:

<?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>

But cannot unmarshal:

但不能解组:

<?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">
        <result>6003</result>
        <ndserr />
        <transid>61437594</transid>
        <descriptionerr>BLAH.</descriptionerr>
    </ns1:responseINFOWL>
</ns1:opINFOWLResponse>

This means that the namespace qualification in your JAXB mappings is incorrect. The following may help:

这意味着 JAXB 映射中的命名空间限定不正确。以下可能有帮助:

If you could post the class that maps to this section of XML, and the package-infoclass if there is one, then I can help you modify the mappings.

如果您可以发布映射到此 XML 部分的package-info类,如果有类,那么我可以帮助您修改映射。