当在CXF服务端pojo中添加一个新属性后,未经重新generate的客户端会在调用该web service时报UnmarshalException: unexpected element,错误日志如下:
DefaultValidationEventHandler: [ERROR]: unexpected element (uri:"", local:"areaId"). Expected elements are <{}dmsSiteCode>,<{}provinceId>,<{}countryId>,<{}mail>,<{}phone>,<{}siteType>,<{}cityId>,<{}orgName>,<{}siteCode>,<{}orgId>,<{}staffNo>,<{}address>,<{}staffName>,<{}subType>,<{}role>,<{}customCode>,<{}sitePhone>,<{}countrySideId>,<{}targetType>,<{}storeCode>,<{}siteName>
Location: line 1
2013-1-5 16:43:20 org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging
警告: Interceptor for {http://webservice.basic.etms.***.com/}BasicForeignWebServiceService#{http://webservice.basic.etms.***.com/}selectSiteBySubtype has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Unmarshalling Error: unexpected element (uri:"", local:"areaId"). Expected elements are <{}dmsSiteCode>,<{}provinceId>,<{}countryId>,<{}mail>,<{}phone>,<{}siteType>,<{}cityId>,<{}orgName>,<{}siteCode>,<{}orgId>,<{}staffNo>,<{}address>,<{}staffName>,<{}subType>,<{}role>,<{}customCode>,<{}sitePhone>,<{}countrySideId>,<{}targetType>,<{}storeCode>,<{}siteName>
at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:773)
at org.apache.cxf.jaxb.JAXBEncoderDecoder.unmarshall(JAXBEncoderDecoder.java:624)
at org.apache.cxf.jaxb.io.DataReaderImpl.read(DataReaderImpl.java:150)
at org.apache.cxf.interceptor.DocLiteralInInterceptor.handleMessage(DocLiteralInInterceptor.java:99)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:244)
at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:664)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:2160)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:2040)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1965)
at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:66)
at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:627)
at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:244)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:478)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:308)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:260)
at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:73)
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:124)
at $Proxy59.selectSiteBySubtype(Unknown Source)
at com.jd.syn.wsFacde.WSClient.initBaseCarrierSynDate(WSClient.java:100)
at com.jd.syn.handler.BaseCarrierSyn.initSyn(BaseCarrierSyn.java:71)
at com.jd.syn.handler.AbstractSyn.execute(AbstractSyn.java:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.util.MethodInvoker.invoke(MethodInvoker.java:273)
at org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean$MethodInvokingJob.executeInternal(MethodInvokingJobDetailFactoryBean.java:264)
at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:86)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:525)
Caused by: javax.xml.bind.UnmarshalException
为了避免反复重新生成客户端代理类,我们必须想一个绕过该Validation的方式。幸运的是,这个问题可以通过提供一个自定义的ValidationEventHandler来解决(仔细看你会发现这个解决方式很取巧)
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
public class IgnoreUnexpectedElementsHandler implements ValidationEventHandler {
@Override
public boolean handleEvent(ValidationEvent event) {
//true: keep going. In this case we only want to continue for the error we're trying to hide.
return event.getMessage().startsWith("unexpected element (");
}
}
之后在你的客户端配置中加入<entry key="jaxb-validation-event-handler" value-ref="ignoreUnexpectedElementsHandler">
具体配置如下:
<jaxws:client id="basicForeignWebService" serviceClass="com.***.syn.ws.basicforeignwebservice.BasicForeignWebService"
address="${promise.basicForeignWebService.ws.wsdl.address}">
<jaxws:outInterceptors>
<ref bean="header" />
</jaxws:outInterceptors>
<jaxws:properties>
<entry key="jaxb-validation-event-handler" value-ref="ignoreUnexpectedElementsHandler">
</entry>
</jaxws:properties>
</jaxws:client>