从WSDL开发Web服务客户端时出现异常

时间:2011-06-28 23:17:44

标签: java wsdl jaxb wsimport

我正在从WSDL创建一个Web服务客户端。

对服务的典型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对象只有一个方法messageBody.setAny(value)。但我需要在其中放置一个DataContainer元素。

我试过传递:

  1. org.w3c.dom.DocumentObject (我得到“javax.xml.ws.soap.SOAPFaultException:无法处理请求。”)probbaly由于xml的删除。
  2. DataContainer 对象,由JAXB从XSD生成(我得到“[javax.xml.bind.JAXBException:类DataContainer或其任何超类都知道此上下文]”)
  3. JAXBElement (我得到“[javax.xml.bind.JAXBException:此类上下文不知道类DataContainer]”)
  4. 我做错了什么?或者我需要做什么才能在邮件正文中获取DataContainer

2 个答案:

答案 0 :(得分:1)

如前所述,您有messageBody.setAny(value),这意味着MessageBody的XSI:type已设置为anytype。这意味着您可以在那里设置任何对象,JAXB应该能够在JAX-WS wsdl2java工具定义的上下文中封送它。从错误消息'无法在Conext中找到DataContainer'看来,您的DataContainer类似乎不在同一个上下文中。

这是一个解决方法,您可以将DataContainer对象编组为JAXBElement<String>(或者可能只是一个字符串,但我不确定它是否可行)对象然后将其设置为anyType。这样你就不会在上下文中得到Class,因为String是一个基本的JAXB类型。

当你尝试使用第2点或第3点时,我不知道你是如何定义你的包结构的,所以我在这里采取狂野的刺。从错误消息中,您似乎单独生成的DataContainer类与Message及其子类不在同一个包中。尝试将DataContainer及其关联的类移动到与Message Class相同的包中,并将两个ObjectFactory类合并在一起。这应该允许JAXB在与Message相同的“上下文”中找到DataContainer。

当您发出实际请求并且JAXB正在编组对象以创建请求时(即JAX-WS在内部调用JAXB Marshelling服务),可能会发生错误。在这种情况下,当您生成客户端时,JAXBContext被设置为Message类所在的包。

这是一个处理JAXBContext Marshaling和unmarshaling的简单教程。 http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/1.6/tutorial/doc/JAXBUsing3.html

同样按照this,您可以将anyType设置为org.w3c.dom.Element而不是org.w3c.dom.Document

答案 1 :(得分:0)

使用xs的秘诀:任何未包含的XSD类型都是@XmlSeeAlso。从xjc工具创建JAXB类时,您将获得一个定义@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。