CXF向后兼容性(backwards compatibility)解决方案

当在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>

 

posted @ 2013-01-06 18:33  栈溢出  阅读(2901)  评论(0编辑  收藏  举报