1

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

我试过通过:

  1. org.w3c.dom.DocumentObject(我得到“javax.xml.ws.soap.SOAPFaultException:无法处理请求。”)可能是由于 xml decleration。
  2. 由 JAXB 从 XSD 生成的DataContainer对象(我得到“[javax.xml.bind.JAXBException: class DataContainer nor any super class is known to this context]”)
  3. JAXBElement(我得到“[javax.xml.bind.JAXBException: class DataContainer is not known to this context]”)

我究竟做错了什么?或者我需要做什么才能在消息正文中获取 DataContainer

4

2 回答 2

1

正如您所提到的,messageBody.setAny(value)这意味着XSI:typefor MessageBody 已设置为anytype. 这意味着您可以在那里设置任何对象,需要注意的是 JAXB 应该能够在 JAX-WS wsdl2java 工具定义的上下文中编组它。从错误消息“在 Conext 中找不到 DataContainer”看来,您的 DataContainer 类不在同一个上下文中。

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

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

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

这是一个处理 JAXBContext 编组和解组的简单教程。 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

于 2011-06-29T07:12:49.877 回答
0

使用 xs:any of non-included 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。

于 2012-08-26T05:28:15.443 回答