Исключение при разработке клиента Webservice из WSDL - PullRequest
1 голос
/ 29 июня 2011

Я создаю клиент веб-сервиса из WSDL.

Типичный SOAP-запрос к сервису выглядит примерно так

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:someGateway">
    <soapenv:Header/>
    <soapenv:Body>
        <urn:send>      
            <urn:message>
                <urn:messageID>1001</urn:messageID>
                <urn:messageBody>
                    <DataContainer>
                        SOME MORE ELEMENTS
                    </DataContainer>
                </urn:messageBody>
            </urn:message>
        </urn:send>
    </soapenv:Body>
</soapenv:Envelope>

Я использовал JAX-WS для генерации артефактов службы и заполнил свои объекты, как показано ниже:

Message message = objectFactory.createMessage();
//Set message ID
String messageID = "123456"
message.setMessageID(messageID );
//Set message Body
MessageBody messageBody = objectFactory.createMessageMessageBody()

Объект messageBody имеет только 1 метод messageBody.setAny (значение). Но мне нужно поместить элемент DataContainer внутри него.

Я попытался передать:

  1. org.w3c.dom.DocumentObject (Я получаю "javax.xml.ws.soap.SOAPFaultException: Не удалось обработать запрос."), Вероятно, из-за удаления xml.
  2. DataContainer объект, сгенерированный JAXB из XSD (я получаю "[javax.xml.bind.JAXBException: класс DataContainer или любой из его суперклассов не известен этому контексту]")
  3. JAXBElement (Я получаю "[javax.xml.bind.JAXBException: класс DataContainer не известен этому контексту]")

Что я делаю не так? Или что мне нужно сделать, чтобы получить DataContainer в теле сообщения

Ответы [ 2 ]

1 голос
/ 29 июня 2011

Как вы упомянули, у вас есть messageBody.setAny(value), что означает, что XSI:type для MessageBody было установлено на anytype. Это означает, что вы можете установить любой объект там, поскольку JAXB должен иметь возможность маршалировать его в контексте, определенном инструментом wsdl2java JAX-WS. Из сообщения об ошибке «Не удается найти DataContainer в Conext» кажется, что ваши классы DataContainer находятся не в том же контексте.

Вот обходной путь для этого, вы, вероятно, можете преобразовать свой объект DataContainer в JAXBElement<String> (или, возможно, просто в String, но я не уверен, что это будет работать), а затем установить его в anyType. Таким образом, вы не получите Class, который не знает в контексте, так как String является базовым типом JAXB.

Я не знаю, как вы определили структуру вашего пакета, когда пытались использовать пункт 2 или 3, поэтому я делаю дикий удар здесь. Из сообщения об ошибке кажется, что ваш отдельно сгенерированный класс DataContainer находится не в том же пакете, что и Message и его подклассы. Попробуйте переместить ваш DataContainer и связанные с ним классы в тот же пакет, что и класс сообщений, и объедините два класса ObjectFactory вместе. Это должно позволить JAXB найти DataContainer в том же «контексте», что и Message.

Ошибка, вероятно, возникает, когда вы делаете фактический запрос, и JAXB выполняет маршалинг объектов для создания запроса (то есть JAX-WS внутренне вызывает службу JAXB Marshelling). В этом случае, когда вы сгенерировали клиент, JAXBContext был установлен на пакет, где класс сообщения.

Вот простое руководство, которое касается JAXBContext Marshaling и unmarshaling. http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.6/tutorial/doc/JAXBUsing3.html

Также в соответствии с этим вы можете установить для anyType значение org.w3c.dom.Element, а не org.w3c.dom.Document

0 голосов
/ 26 августа 2012

Секрет использования xs: любого из не включенных типов XSD - @XmlSeeAlso. При создании классов JAXB из инструмента xjc вы получите интерфейс, определяющий методы @WebService. Этот интерфейс также будет использоваться реализацией клиента и сервиса. Если вы не хотите изменять автоматически сгенерированные Java-файлы, вам лучше расширить этот интерфейс в вашем пакете и добавить @XmlSeeAlso({ExternalClassYouWantToReferTo.class}) в этот новый интерфейс, например: IWebServiceInterface

@WebService(name = "IExternalXmlBatchReceive", targetNamespace = "http://External.ServiceContract.BatchReceive")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({
    ObjectFactory.class, ExternalClassYouWantToReferTo.class
})
public IWebServiceInterface extends InterfaceYourAutoCreationCode {
@WebMethod(name=...)
 ......
}

Все ваши Service класс и @WebService реализованы с помощью этого интерфейса.

Когда ваш клиент вызывает метод getPort, вы должны передать ваш новый реализованный интерфейс в качестве второго параметра, например:

IWebServiceInterface wi = service.getPort(YOUR_QNAME, IWebServiceInterface.class);

Метод getPort проверяет интерфейс, который вы передали для @XmlSeeAlso, и инициализирует его внутренний JAXBContext.

...