我们有几个基于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文件中可以看到,这里定义了两个操作:listMessages
和getMessageDetail
- 引物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
失败了?
答案 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>
......