org.apache.cxf.binding.soap.SoapFault:解组错误:cvc-elt.1.a:找不到元素'ns1:RequestMetaData'的声明

时间:2013-11-19 14:57:30

标签: java soap jaxb cxf apache-camel

我们有几个基于SOAP的Web服务,有些是通过Apache CXF直接通过合同第一种方式公开的,有些是通过Apache Camel及其CXF扩展公开的服务。到目前为止,我们使用PAYLOAD方法作为CxfSpringEndpoint的数据格式,但随着需求的变化,我必须将数据格式更改为POJO,而不是直接通过Camel的消息体启用解组对象。

更改代码以在Camel中启用POJO数据格式处理后,我遇到了以下异常:Caused by: org.apache.cxf.binding.soap.SoapFault: Unmarshalling Error: cvc-elt.1.a: Cannot find the declaration of element 'ns1:RequestMetaData'.仅在调用特定操作(getMessageDetail)时抛出。

端点配置确实在工厂的CxfSpringEndpoint.setWsdlURL(...)方法中设置了WSDL,甚至为已定义的模式添加了模式。省略WSDL文件会导致Invalid schema document passed to AbstractDataBinding.addSchemaDocument, not in W3C schema namespace: {http://www.w3.org/1999/xhtml}html异常,尽管已添加了模式(和子模式)。

WSDL文件类似于:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" 
    xmlns:hub="http://namespace.hub.com"
    targetNamespace="http://namespace.hub.com">

    <wsdl:types>
        <xs:schema>
            <xs:import namespace="http://namespace.hub.com" schemaLocation="xsd/hub.xsd" />
        </xs:schema>
    </wsdl:types>

    ...

    <!-- listMessages -->
    <wsdl:message name="listMessagesRequest">
        <wsdl:part name="in" element="hub:ListMessagesRequest" />
    </wsdl:message>
    <wsdl:message name="listMessagesResponse">
        <wsdl:part name="out" element="hub:ListMessagesResponse" />
    </wsdl:message>

    <!-- getMessagDetail -->
    <wsdl:message name="getMessageDetailRequest">
        <wsdl:part name="in" element="hub:GetMessageDetailRequest" />
    </wsdl:message>
    <wsdl:message name="getMessageDetailResponse">
        <wsdl:part name="out" element="hub:GetMessageDetailResponse" />
    </wsdl:message>

    ...
</wsdl:definitions>

导入的架构定义为:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema 
    targetNamespace="http://namespace.hub.com" 
    xmlns:tns="http://namespace.hub.com"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified"
    attributeFormDefault="qualified">

    ...
    <xs:element name="ListMessagesRequest" type="tns:ListMessagesRequestType" />
    <xs:element name="ListMessagesResponse" type="tns:ListMessagesResponseType" />
    <xs:element name="GetMessageDetailRequest" type="tns:GetMessageDetailRequestType" />
    <xs:element name="GetMessageDetailResponse" type="tns:GetMessageDetailResponseType" />
    ...

    <xs:complexType name="AbstractRequestType" abstract="true">
        <xs:sequence>
            <xs:element name="RequestMetaData" >
                <xs:complexType>
                    <xs:sequence>
                        <!-- some meta data necessary for all messages -->
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="ListMessagesRequestType">
        <xs:complexContent>
            <xs:extension base="tns:AbstractRequestType">
                <xs:sequence>
                    <xs:element name="Limit" type="xs:int" minOccurs="0" maxOccurs="1" />
                    <xs:element name="Offset" type="xs:int" minOccurs="0" maxOccurs="1" />
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    <xs:complexType name="GetMessageDetailRequestType">
        <xs:complexContent>
            <xs:extension base="tns:AbstractRequestType">
                <xs:sequence>
                    <xs:element name="MessageId" type="xs:string" minOccurs="1" maxOccurs="1" />
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    ...
</xs:schema>

WSDL和XSD都是不完整的,并且命名空间已经更改,以便将重点更多地放在必要的东西上。正如希望从WSDL文件中可以看到,这里定义了两个操作:listMessagesgetMessageDetail - 引物1返回一个接收消息列表,可以通过使用限制和偏移参数进一步分页。后者返回收到消息的详细信息,因此只需要消息ID。这两条消息都需要在SOAP消息中传递额外的元数据。

在执行UnitTests时,除getMessageDetail之外的所有测试都成功 - 这包括listMessages操作的调用,其定义方式与getMessageDetail相同。以下是UnitTest的代码摘录

try
{
    final DeliveryEndpoint client = createDeliveryClient(userid, userkey);

    // first send 3 valid messages
    this.sendMultipleMessages(client);

    ListMessagesResponse response = client.listMessages(
        new ListMessagesRequest()
            .withRequestMetaData(getRMD()));

    Assert.assertNotNull(response);
    List<MessagesInfoType> infos = response.getMessageInfos();
    Assert.assertEquals(3, infos.size());

    GetMessageDetailResponse detailResponse = client.getMessageDetail(
        new GetMessageDetailRequest()
            .withRequestMetaData(getRMD())
            .withMessageId(infos.get(1).getMessageId()));

    Assert.assertNotNull(detailResponse);
    MessageDetailType details = detailResponse.getMessageDetail();
    Assert.assertNotNull(details);
    ...
}
catch(Exception e)
{
    e.printStackTrace();
    Assert.fail("Exception caught: "+e.getLocalizedMessage());
}

在执行UnitTest时,我获得了propper SOAP消息,但是一旦Camel收到以下SOAP请求,它就会抛出SOAP消息下面列出的异常。请注意,先前的服务调用已成功,因此这仅影响getMessageDetail操作!

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <ns1:GetMessageDetailRequest 
            xmlns:ns1="http://namespace.hub.com">

            <ns1:RequestMetaData>
                <!-- the specified meta data-->
            </ns1:RequestMetaData>

            <ns1:MessageId>someMessageId</ns1:MessageId>
        </ns1:GetMessageDetailRequest>
    </soap:Body>
</soap:Envelope>

堆栈跟踪:

org.apache.cxf.interceptor.Fault: Unmarshalling Error: cvc-elt.1.a: Cannot find the declaration of element 'ns1:RequestMetaData'. 
    at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:808) ~[cxf-rt-databinding-jaxb-2.7.5.jar:2.7.5]
    at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:629) ~[cxf-rt-databinding-jaxb-2.7.5.jar:2.7.5]
    at org.apache.cxf.jaxb.io.DataReaderImpl.read(DataReaderImpl.java:157) ~[cxf-rt-databinding-jaxb-2.7.5.jar:2.7.5]
    at org.apache.cxf.interceptor.DocLiteralInInterceptor.getPara(DocLiteralInInterceptor.java:321) ~[cxf-api-2.7.4.jar:2.7.4]
    at org.apache.cxf.interceptor.DocLiteralInInterceptor.handleMessage(DocLiteralInInterceptor.java:121) ~[cxf-api-2.7.4.jar:2.7.4]
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:271) ~[cxf-api-2.7.4.jar:2.7.4]
    at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) ~[cxf-api-2.7.4.jar:2.7.4]
    at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.serviceRequest(JettyHTTPDestination.java:355) ~[cxf-rt-transports-http-jetty-2.7.4.jar:2.7.4]
    at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.doService(JettyHTTPDestination.java:319) ~[cxf-rt-transports-http-jetty-2.7.4.jar:2.7.4]
    at org.apache.cxf.transport.http_jetty.JettyHTTPHandler.handle(JettyHTTPHandler.java:72) ~[cxf-rt-transports-http-jetty-2.7.4.jar:2.7.4]
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1040) ~[jetty-server-7.6.8.v20121106.jar:7.6.8.v20121106]
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:976) ~[jetty-server-7.6.8.v20121106.jar:7.6.8.v20121106]
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135) ~[jetty-server-7.6.8.v20121106.jar:7.6.8.v20121106]
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:255) ~[jetty-server-7.6.8.v20121106.jar:7.6.8.v20121106]
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116) ~[jetty-server-7.6.8.v20121106.jar:7.6.8.v20121106]
    at org.eclipse.jetty.server.Server.handle(Server.java:363) ~[jetty-server-7.6.8.v20121106.jar:7.6.8.v20121106]
    at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:483) ~[jetty-server-7.6.8.v20121106.jar:7.6.8.v20121106]
    at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:931) ~[jetty-server-7.6.8.v20121106.jar:7.6.8.v20121106]
    at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:992) ~[jetty-server-7.6.8.v20121106.jar:7.6.8.v20121106]
    at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:856) ~[jetty-http-7.6.8.v20121106.jar:7.6.8.v20121106]
    at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:240) ~[jetty-http-7.6.8.v20121106.jar:7.6.8.v20121106]
    at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82) ~[jetty-server-7.6.8.v20121106.jar:7.6.8.v20121106]
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:628) ~[jetty-io-7.6.8.v20121106.jar:7.6.8.v20121106]
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52) ~[jetty-io-7.6.8.v20121106.jar:7.6.8.v20121106]
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608) ~[jetty-util-7.6.8.v20121106.jar:7.6.8.v20121106]
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543) ~[jetty-util-7.6.8.v20121106.jar:7.6.8.v20121106]
    at java.lang.Thread.run(Thread.java:724) ~[na:1.7.0_25]
Caused by: javax.xml.bind.UnmarshalException: null
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:431) ~[jaxb-impl-2.2.2.jar:2.2.2]
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:368) ~[jaxb-impl-2.2.2.jar:2.2.2]
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:345) ~[jaxb-impl-2.2.2.jar:2.2.2]
    at org.apache.cxf.jaxb.JAXBEncoderDecoder.doUnmarshal(JAXBEncoderDecoder.java:769) ~[cxf-rt-databinding-jaxb-2.7.5.jar:2.7.5]
    at org.apache.cxf.jaxb.JAXBEncoderDecoder.access$100(JAXBEncoderDecoder.java:94) ~[cxf-rt-databinding-jaxb-2.7.5.jar:2.7.5]
    at org.apache.cxf.jaxb.JAXBEncoderDecoder$1.run(JAXBEncoderDecoder.java:797) ~[cxf-rt-databinding-jaxb-2.7.5.jar:2.7.5]
    at java.security.AccessController.doPrivileged(Native Method) ~[na:1.7.0_25]
    at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:795) ~[cxf-rt-databinding-jaxb-2.7.5.jar:2.7.5]
    ... 26 common frames omitted
Caused by: org.xml.sax.SAXParseException: cvc-elt.1.a: Cannot find the declaration of element 'ns1:RequestMetaData'.
    at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source) ~[xercesImpl-2.10.0.jar:na]
    at org.apache.xerces.util.ErrorHandlerWrapper.error(Unknown Source) ~[xercesImpl-2.10.0.jar:na]
    at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source) ~[xercesImpl-2.10.0.jar:na]
    at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source) ~[xercesImpl-2.10.0.jar:na]
    at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source) ~[xercesImpl-2.10.0.jar:na]
    at org.apache.xerces.impl.xs.XMLSchemaValidator.handleStartElement(Unknown Source) ~[xercesImpl-2.10.0.jar:na]
    at org.apache.xerces.impl.xs.XMLSchemaValidator.startElement(Unknown Source) ~[xercesImpl-2.10.0.jar:na]
    at org.apache.xerces.jaxp.validation.ValidatorHandlerImpl.startElement(Unknown Source) ~[xercesImpl-2.10.0.jar:na]
    at com.sun.xml.bind.v2.runtime.unmarshaller.ValidatingUnmarshaller.startElement(ValidatingUnmarshaller.java:101) ~[jaxb-impl-2.2.2.jar:2.2.2]
    at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.handleStartElement(StAXStreamConnector.java:247) ~[jaxb-impl-2.2.2.jar:2.2.2]
    at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(StAXStreamConnector.java:181) ~[jaxb-impl-2.2.2.jar:2.2.2]
    at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:366) ~[jaxb-impl-2.2.2.jar:2.2.2]
    ... 32 common frames omitted

所以问题是,为什么listMessages的调用成功(有和没有可选参数)但是getMessageDetail失败了?

1 个答案:

答案 0 :(得分:0)

(在问题编辑中由OP回答。转换为社区维基答案。请参阅Question with no answers, but issue solved in the comments (or extended in chat)

OP写道:

  

经过一些测试时间后,似乎Apache CXF使用的Xerces版本有问题,因为它需要<xs:choice>定义中的<xs:sequence>子元素才能正常工作。

     

因此,更改上述架构以匹配以下结构可解决异常:

<xs:complexType name="GetMessageDetailRequestType">
    <xs:complexContent>
        <xs:extension base="tns:AbstractRequestType">
            <xs:sequence>
                <xs:choice>
                    <xs:element name="MessageId" type="xs:string" minOccurs="1" maxOccurs="1" />
                </xs:choice>
            </xs:sequence>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>

<xs:complexType name="GetMessageDetailResponseType">
    <xs:sequence>
        <xs:choice>
            <xs:element name="MessageDetail" type="tns:MessageDetailType" />
        </xs:choice>
    </xs:sequence>
</xs:complexType>
  

而不是<xs:choice>也可以使用<xs:sequence> ......