2016-06-23 93 views
4

我有一個流在CXF客戶端我有攔截器,提供程序和異常映射器的jaxrs。在我的情況下,我通過攔截器捕獲客戶的不良響應,然後我想中止cxf總線鏈並拋出一個錯誤。不幸的是我無法做到這一點,因爲在每一種情況下,攔截器拋出的異常都只被記錄下來,但主錯誤(錯誤的json格式)傳播到異常映射器。我想避免Exception mapper,但我不知道如何。我使用Web客戶端來實現這樣的攔截器:從CXF攔截器傳播異常到異常映射器

@Component 
public class MyInterceptor extends AbstractPhaseInterceptor<Message> { 

    public MyInterceptor() { 
     super(POST_STREAM); 
    } 

    @Override 
    public void handleMessage(Message message) throws Fault { 
     if (message != null) { 
       //message.getExchange().setOneWay(true); 
       //message.getExchange().put(Exception.class, new MyException()); 
       //message.getInterceptorChain().abort(); 
       //message.setContent(Exception.class, new MyException()); 
       //Endpoint ep = message.getExchange().get(Endpoint.class); 
       //message.getInterceptorChain().abort(); 
       //if (ep.getInFaultObserver() != null) { 
       // ep.getInFaultObserver().onMessage(message); 
       //} 
       //throw new WebApplicationException(new MyException()); 

       //message.setContent(Response.class, response); 
       throw new Fault(new MyException()); 
      } 
     } 

我讀,我應該實現由攔截器拋出不會傳播到異常映射JAXRS過濾器導致異常。感謝WebClient實現,是否有任何方法可以在java中實現?

S client = create(url, clazz, list(jsonProvider(), providers)); 
WebClient.getConfig(client).getInInterceptors().add(new MyInterceptor()); 

我也試過在攔截器上使用不同的階段,但它也沒有工作。

回答

4

我一直在研究和測試你的問題。問題是,從CXF攔截器拋出的異常逃生(CXF團隊see the answer)的JAX-RS流

一個由攔截器產生Fault可以被獲取,在攔截器實現handleFault本身

public void handleFault(Message message) { 
     Exception e = message.getContent(Exception.class); 
} 

或實施一個FaultListener和CXF總線

WebClient.getConfig(client).getBus().getProperties().put("org.apache.cxf.logging.FaultListener",new MyFaultListener()); 

public class MyFaultListener implements FaultListener{ 
    public boolean faultOccurred(final Exception exception,final String description,final Message message) { 
     //return false to avoid warning of default CXF logging interceptor 
     return false; 
    } 
} 

註冊,但你不能從攔截返回自定義響應或響應一個故障給客戶。

我已經找到了實現期望的行爲的解決方法在於更換與可能由普通方法invokation處理自定義對象的響應,像exceptionMapper 見CXF/ JAX-RS : Return Custom response from interceptor

進入Interceptor.handleMessage檢查的條件你需要並創建一個帶自定義狀態和實體的Response。在此之後,停止鏈

public class MyInterceptor extends AbstractPhaseInterceptor<Message> { 

    public MyInterceptor() { 
     super(Phase.POST_STREAM); 
    } 

    @Override 
    public void handleMessage(Message message) throws Fault { 
     if (message != null) { 
      //check the condition to raise the error 
      //build the custom Response replacing service call 
      Response response = Response 
        .status(Response.Status.BAD_REQUEST) 
        .entity("custom error") 
        .build(); 
      message.getExchange().put(Response.class, response); 

      //abort interceptor chain in you want to stop processing or throw a Fault (catched by handleFault) 
      //message.getInterceptorChain().abort(); 
      //throw new Fault (new MyException()); 

     } 

    public void handleFault(Message messageParam) { 
    } 
} 

創建JAXRS客戶

providers.add(new ResponseExceptionMapper<WebApplicationException>() { 

    @Override 
    public WebApplicationException fromResponse(Response r) { 
     return new WebApplicationException(r); 
    } 

}); 

YourService proxy = JAXRSClientFactory.create(url, clazz,providers); 
Client client = WebClient.client(proxy); 
WebClient.getConfig(client).getInInterceptors().add(new MyInterceptor()); 

此之後,當添加ResponseExceptionMapper作爲提供商,proxy.yourService()通話將引發WebApplicationException如果acomplish攔截檢查。你可以將其接住或以希望的方式重新拋出

try{ 
    proxy.yourService(); 
}catch (WebApplicationException e){ 
} 

希望這有助於

0

我完全與以前的答案達成一致。我的實現是這樣的:

@Component 
public class ServiceFailureInterceptor extends AbstractPhaseInterceptor<Message> { 

    private static final Logger LOG = LoggerFactory.getLogger(ServiceFailureInterceptor.class); 

    public ServiceFailureInterceptor() { 
     super(PRE_STREAM); 
    } 

    @Override 
    public void handleMessage(Message message) { 
     if (message != null) { 
      int responseCode = (int) message.get(Message.RESPONSE_CODE); 
       LogicException logicException = ErrorMapper.HTTP_STATUS_CODE_MAPPER.get(responseCode); 
       InputStream is = b2stream(MapperUtils.json().toBytes(logicException)); 

       // clear old message & exchange 
       Exchange exchange = message.getExchange(); 
       for (Class<?> contentFormat : message.getContentFormats()) { 
        message.setContent(contentFormat, null); 
       } 

       resetOrigInterceptorChain(message); 
       resetFault(exchange); 

       message.setContent(InputStream.class, is); 
       Message outMessage = createOutMessage(exchange, is); 
       prepareMessage(outMessage); 
       prepareMessage(message); 
     } 
    } 

    private void prepareMessage(Message message) { 
     message.put(Message.REQUESTOR_ROLE, true); 
     message.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON); 
    } 


    private Message createOutMessage(Exchange exchange, InputStream logicException) { 
     Endpoint ep = exchange.get(Endpoint.class); 
     Message outMessage = ep != null ? ep.getBinding().createMessage() : new MessageImpl(); 
     outMessage.setContent(InputStream.class, logicException); 
     exchange.setOutMessage(outMessage); 
     outMessage.setExchange(exchange); 
     return outMessage; 
    } 

    private void resetFault(Exchange exchange) { 
     exchange.put(Exception.class, null); 
    } 

    private void resetOrigInterceptorChain(Message message) { 
     InterceptorChain chain = message.getInterceptorChain(); 
     if (chain != null) { 
      for (Interceptor<?> interceptor : chain) { 
       chain.remove(interceptor); 
      } 
      chain.reset(); 
     } 
    } 
} 

手動設置這個異常後,在我的LogicException消耗和響應與異常建立我打算ExceptionMapper實施。當我通過WebClient聲明爲提供者時,我無法避免異常映射器,因此我決定使用它並稍後重新映射Exception。