Exception handling cxf中使用客户端(javax.ws.rs.Client.Client)API的ResponseExceptionMapper

Exception handling cxf中使用客户端(javax.ws.rs.Client.Client)API的ResponseExceptionMapper,exception-handling,cxf,cxf-client,restclientbuilder,Exception Handling,Cxf,Cxf Client,Restclientbuilder,此帖子无法解决以下问题:。您会注意到,我实际上注册并注释了我的提供者,并且按照建议尝试了WebApplicationException,而不是Exception/CustomException 问题陈述:无法使用客户端(javax.ws.rs.client.client)API和实现ResponseExceptionMapper接口的@Provider类实现自定义客户端异常处理程序 问题: 客户端API是否不支持用于异常处理的自定义客户端提供程序 我查找的关于这个问题陈述的任何文献都使用JAXR

此帖子无法解决以下问题:。您会注意到,我实际上注册并注释了我的提供者,并且按照建议尝试了WebApplicationException,而不是Exception/CustomException

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

问题:

  • 客户端API是否不支持用于异常处理的自定义客户端提供程序
  • 我查找的关于这个问题陈述的任何文献都使用JAXRSClientFactory实现;我还没有找到任何用于此场景的客户端API。我必须切换我的实现吗
  • 客户端API和JAXRSClientFactory实现之间的区别是什么
  • 我正在用Java开发cxf客户端API实现,注意到对于300以上的http状态代码,cxf将响应包装在WebApplicationException或ProcessingException中(取决于响应状态代码)。在我的例子中,服务器有一个定制的响应主体,指示http状态代码的实际原因!200,如下所示(响应代码=412):

    不幸的是,WebApplicationException本身并没有呈现这种情况。相反,在异常中直接捕获的唯一消息是通用的“412前置条件失败”。我可以从代码段(包括客户端API代码段)执行类似于以下异常块的操作:

    protectedrespobj invoke(字符串endPointUrl)引发CustomException{
    对象reqPOJO=prepareRequest();
    试一试{
    if(客户端==null){
    ClientBuilder=ClientBuilder.newBuilder();
    //注册自定义JAX-RS组件
    注册(新的CustomMapper());
    }
    WebTarget target=client.target(endPointUrl);
    //当查询参数存在时执行此操作
    如果(!getUriParams().isEmpty()){
    对于(Map.Entry queryParams:getUriParams().entrySet()){
    target=target.queryParam(queryParams.getKey(),queryParams.getValue());
    }
    }
    Invocation.Builder=target.request();
    //在这里创建标题
    MultivaluedMap headers=新的MultivaluedHashMap();
    如果(isBasicAuthRequired()){
    添加(AUTH_HEADER_参数,getBasicAuthentication());
    }
    headers.add(CONTENT_TYPE,getMediaType().toString());
    标题(标题);
    accept(getMediaType().toString());
    //投递
    if(HttpMethodType.GET.equals(getHttpMethod())){
    返回builder.get(RESPOBJ.class);
    }
    返回builder.post(Entity.Entity(reqPOJO,getMediaType()),RESPOBJ.class);
    }
    捕获(例外情况除外){
    if(响应处理异常的实例){
    ResponseProcessingException e=(ResponseProcessingException)ex;
    logger.error(“解组失败:[“+e.getResponse().readEntity(String.class)+“]”);
    }
    else if(例如WebApplicationException的实例){
    WebApplicationException e=(WebApplicationException)ex;
    logger.error(“错误响应:[“+e.getResponse().readEntity(String.class)+“]”);
    }
    抛出新的CustomException(ex);
    }
    }
    
    不过,我希望实现更干净的东西,最好使用实现ResponseExceptionMapper接口的自定义异常处理程序。从文献中我注意到,用于自定义客户端异常处理的ResponseExceptionMapper的唯一实现是使用JAXRSClientFactory。但是,我当前的实现使用客户端API(下面的代码片段)。从设计方面来说,我将对其进行修改,使其具有一个单独的CustomExceptionMapper类,该类仅在异常情况下作为提供程序,但我不明白为什么该自定义类注册为提供程序(作为MBR适用于200个状态代码,MBW始终适用),但不适用于异常情况

    更新:在调试和观察200 vs>300状态代码(在我的示例中为412)之间的更改时,我注意到,对于200个示例,调用了JAXRSUtils.readFromMessageBodyReader()方法,这是第一次检索自定义提供程序。下面代码片段中显示的状态代码的代码永远不会出现在这里,这应该是找不到CustomMapper的原因。我必须如何注册CustomExceptionMapper有什么不同吗?或者客户端API根本不支持此功能?

    //对于失败案例,上面的方法返回null(状态>300),而对于成功案例200,它执行最后一行中的方法并获取提供程序。 //AbstractClient类,该类调用doReadEntity()方法,该方法反过来在JAXRSUtils.readFromMessageBodyReader()方法代码中调用并查找提供程序

    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);
        }
    }
    
    受保护的T读卡器(响应r、消息输出消息、类别cls、,
    类型,注释[]anns){
    if(cls==Response.class){
    返回cls.cast(r);
    }
    int status=r.getStatus();
    //这是针对失败案例调用的
    if((状态<200 | |状态==204)和&r.getLength()=300){
    返回null;
    }
    //这是200状态代码
    return((ResponseImpl)r).doReadEntity(cls,type,anns);
    }
    //我的自定义提供程序代码
    @提供者
    @消耗
    @产生(MediaType.APPLICATION_JSON)
    公共类CustomMapper实现MessageBodyReader、MessageBodyWriter、ResponseExceptionMapper{
    private Gson Gson=new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
    @凌驾
    公共布尔值可读取(类类型、类型genericType、注释[]注释、MediaType MediaType){
    返回类型.isAssignableFrom(CustomResponse.class);
    }
    @凌驾
    公共CustomResponse readFrom(类类型、类型genericType、注释[]注释
    
    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);
        }
    }
    
    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);
        }
    }