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

原文:http://www.cnblogs.com/qunyang/archive/2013/01/06/2848158.html?utm_source=tuicool
当在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 (");
}
}
之后在你的客户端配置中加入 
具体配置如下:
<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>

 

你可能感兴趣的:(java)