使用Client(javax.ws.rs.client.Client)API

时间:2017-06-15 23:29:59

标签: exception-handling cxf cxf-client restclientbuilder

此帖子无法解决问题:ResponseExceptionMapper in cxf client。您会注意到我确实注册并注释了我的Provider,并且我尝试使用WebApplicationException而不是Exception / CustomException。

问题陈述:无法使用Client(javax.ws.rs.client.Client)API和实现ResponseExceptionMapper接口的@Provider类实现自定义客户端异常处理程序。

问题:

  1. Client API是否不支持用于异常处理的自定义客户端提供程序?
  2. 我为此问题语句查找的任何文献都使用JAXRSClientFactory实现;我还没有找到任何使用Client API的方案。我是否必须切换我的实施?
  3. Client API和JAXRSClientFactory实现之间有什么区别?
  4. 我正在使用Java中的cxf客户端API实现,并注意到对于高于300的http状态代码,cxf将响应包装在WebApplicationException或ProcessingException中(取决于响应状态代码)。在我的情况下,服务器有一个自定义的响应主体,指示http状态代码的实际原因!200,如下所示(响应代码= 412):

    {
    "requestError": {
      "serviceException": {
           "messageId": "SVC4120",
           "text": "Invalid Request: Invalid Coupon Code."
        }
      }
    }
    

    不幸的是,WebApplicationException本身不会渲染它。相反,直接在异常中捕获的唯一消息是通用的“412 Precondition Failed”。我可以在代码片段(包括客户端API代码段)中执行类似于以下异常块的操作:

    protected RESPOBJ invoke(String endPointUrl) throws CustomException {
        Object reqPOJO = prepareRequest();
        try {
            if(client == null) {
                ClientBuilder builder = ClientBuilder.newBuilder();
                //register custom JAX-RS components
                builder.register(new CustomMapper());
            }
            WebTarget target = client.target(endPointUrl);
            //do this when queryParams exist
            if(!getUriParams().isEmpty()) {
                for(Map.Entry<String, String> queryParams : getUriParams().entrySet()) {
                    target = target.queryParam(queryParams.getKey(), queryParams.getValue());
                }
            }
            Invocation.Builder builder = target.request();
            //create headers here
            MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
            if(isBasicAuthRequired()) {
                headers.add(AUTH_HEADER_PARAM, getBasicAuthentication());
            }
            headers.add(CONTENT_TYPE, getMediaType().toString());
            builder.headers(headers);
            builder.accept(getMediaType().toString());
            //GET or POST
            if(HttpMethodType.GET.equals(getHttpMethod())) {
                return builder.get(RESPOBJ.class);
            }
            return builder.post(Entity.entity(reqPOJO, getMediaType()), RESPOBJ.class);
        }
        catch (Exception ex) {
            if(ex instanceof ResponseProcessingException) {
                ResponseProcessingException e = (ResponseProcessingException) ex;
                logger.error("Unmarshalling failed: [" + e.getResponse().readEntity(String.class) + "]");
            }
            else if(ex instanceof WebApplicationException) {
                WebApplicationException e = (WebApplicationException) ex;
                logger.error("Error Response: ["+e.getResponse().readEntity(String.class) + "]");
            }
            throw new CustomException(ex);
        }
    }
    

    但是,我希望实现更清洁的东西,最好使用实现ResponseExceptionMapper&lt;&gt;的自定义异常处理程序。接口。从文献中我注意到,用于自定义客户端异常处理的ResponseExceptionMapper的唯一实现是使用JAXRSClientFactory。但是,我当前的实现使用Client API(下面的代码段)。从设计方面我将修改它以具有单独的CustomExceptionMapper类,该类仅作为Exception情况的Provider,但我不明白为什么这个Custom类被注册为Provider(适用于200状态代码作为MBR,以及MBW)总是有效)但不适用于例外情况。

    更新:在调试和观察200 vs&gt; 300状态代码(在我的情况下为412)之间的变化时,我注意到200个案例JAXRSUtils.readFromMessageBodyReader()方法被调用,这是第一次检索自定义提供商。对于代码片段中显示的状态代码,代码永远不会出现在此处,这应该是找不到CustomMapper的原因。我必须注册我的CustomExceptionMapper有什么不同吗?或者Client API是否不支持此功能?

    //对于失败案例,上述方法返回null(状态&gt; 300),而对于成功200案例,它在最后一行执行方法并获取提供者。 //调用doReadEntity()方法的AbstractClient类,该方法在JAXRSUtils.readFromMessageBodyReader()方法代码中调用并查找Provider

    protected <T> T readBody(Response r, Message outMessage, Class<T> cls, 
                             Type type, Annotation[] anns) {
    
        if (cls == Response.class) {
            return cls.cast(r);
        }
    
        int status = r.getStatus();
    
        //this is invoked for failure case
        if ((status < 200 || status == 204) && r.getLength() <= 0 || status >= 300) {
            return null;
        }
        //this for 200 status code
        return ((ResponseImpl)r).doReadEntity(cls, type, anns);                                                
    }
    
    //My custom provider code
    @Provider
    @Consumes
    @Produces(MediaType.APPLICATION_JSON)
    public class CustomMapper implements MessageBodyReader<CustomResponse>, MessageBodyWriter<CustomRequest>, ResponseExceptionMapper<CustomException> {
        private Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
    
        @Override
        public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
            return type.isAssignableFrom(CustomResponse.class);
        }
    
        @Override
        public CustomResponse readFrom(Class<CustomResponse> type, Type genericType, Annotation[] annotations,
            MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
            CustomResponse respObj = new CustomResponse();
            //json to pojo code
            return respObj;
        }
    
        @Override
        public long getSize(CustomRequest reqObj, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
            return -1;
        }
    
        @Override
        public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
            return type.isAssignableFrom(CustomRequest.class);
        }
    
        @Override
        public void writeTo(CustomRequest reqObj, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType,
            MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
            entityStream.write(gson.toJson(reqObj).getBytes());
        }
    
        @Override
        public CustomException fromResponse(Response exceptionResponse) {
            //Response obj to my CustomException code
            return (CustomException);
        }
    }
    

    问题:

    我试图弄清楚这里做错了什么,以及Client API是否因任何原因不支持自定义客户端异常处理? Client API和JAXRSClientFactory实现之间有什么区别? 我也在考虑使用ClientResponseFilter(尚未尝试过)。

    任何帮助表示赞赏。感谢。

0 个答案:

没有答案