Мой клиент веб-сервиса jax-ws возвращает только пустые объекты - PullRequest
8 голосов
/ 24 августа 2011

У меня есть сторонний веб-сервис, для которого я создаю клиента с помощью wsimport. Каждый вызов веб-службы завершается успешно, но у объекта ответа, который я получаю, все его поля установлены в нуль. Наблюдая за сетью, я вижу, что в сети все элементы XML в ответном сообщении содержат значения, поэтому объект должен иметь ненулевые данные. Кроме того, клиент для той же службы, созданной со старой осью 1 и вызванной с теми же данными, возвращает непустой ответ. Есть идеи, что происходит? (На случай, если будет какая-то разница, я использую реализацию JAXB от MOXy).

Обновление : я смог сузить его. 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 ...

и unmarshalled к ненулевому 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();

и я получаю тот же результат. Если я изменю 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 сентября) : Представленное ниже предложение о неверной квалификации пространства имен интересно, но я предположил, что 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 класса

<code>/*
 * <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>
 * 
* * * / @XmlAccessorType (XmlAccessType.FIELD) @XmlType (name = "responseINFOWL", propOrder = { "result", "descriptionerr", "transid", "ndserr", "wallet"}) открытый класс ResponseINFOWL { @XmlElement (обязательно = true) результат защищенной строки; @XmlElement (обязательно = true) защищенный String descriptionerr; @XmlElement (обязательно = true) защищенная строка; защищенная строка ndserr; защищенный кошелек TWallet; // геттеры, сеттеры и все. }

Я попытался немного поиграть с пространствами имен в package-info, но все еще не радует.

Ответы [ 2 ]

3 голосов
/ 26 сентября 2016

Недавно я столкнулся с той же самой проблемой, с которой вы столкнулись, и все сводилось к тому, что служба, с которой я связывался, возвращала нечто отличное от того, что рекламировалось в его WSDL. Служба использовала старую версию Apache Axis (1.4), поведение которой конфликтует с текущими реализациями JAX-WS.

В частности, пространство имен фактического содержимого тела ответа НЕ было ожидаемым клиентским кодом, сгенерированным утилитой wsimport JAX-WS. Например, фактический ответ выглядел примерно так, с 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, ожидали чего-то похожего на ответ ниже, с элементом 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>

Поскольку я не мог изменить службу, которую я потреблял, я вместо этого сам написал новый WSDL, который использовал обернутую привязку doc-литерал для явного управления ожидаемой структурой ответа (и, конечно, запроса). Существует действительно хорошая статья о типах связывания WSDL для IBM Developerworks.

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 для создания клиентских заглушек, которые идеально работают со службой. Кроме того, с помощью обёрнутого документа-буквального подхода я полностью контролирую ожидаемую структуру и пространство имен запроса / ответа, поэтому при необходимости могу реализовать несколько пространств имен в этом XML.

Наслаждайтесь ...

1 голос
/ 09 сентября 2011

Пожалуйста, исправьте меня, если у меня неверный вариант использования.

Вы можете демаршировать:

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

Но не может разобрать:

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

Это означает, что квалификация пространства имен в ваших сопоставлениях JAXB неверна. Следующее может помочь:

Если бы вы могли опубликовать класс, который сопоставляется с этим разделом XML, и класс package-info, если он есть, тогда я могу помочь вам изменить сопоставления.

...