Hi, Just a short answers:
> 1) Does Client API not support custom client side providers for exception > handling? No. It is not part of JAX-RS specification. Spec defines server side exception mappers only: see " 4.4 Exception Mapping Providers": "Note that exception mapping providers are not supported as part of the Client API". Principally response -> exception mapping can be done in JAX-RS ClientResponseFilter. > 2) Any literature I looked up for this problem statement uses > JAXRSClientFactory implementation; I'm yet to find any using Client API for > this scenario. Would I have to switch my implementation? CXF provides proprietary client side exception mapper: ResponseExceptionMapper. It designed to be used only with proxy based JAXRSClientFactory. Which API you use, it really depends on your use case. Sometimes web centric Client API is handy, sometimes - proxy based one. JAX-RS spec concentrates on web centric client API as pure REST one. >3) What is the difference between Client API and JAXRSClientFactory >implementations Client API is web based, you explicitly operate with URIs, resources, media types, response codes. JAXRSClientFactory is proxy based, you will get a proxy for the service interface containing JAX-RS annotations. After that you just invoke proxy methods. URIs, resources, media types are transparent for client. Please take a look in this documentation to understand the differences: http://cxf.apache.org/docs/jax-rs-client-api.html I see following options: 1) Keep Client API and implement exception mapper as ClientResponseFilter 2) Keep Client API and explicitly check responses after invocation to throw appropriate exception 3) Use proxy based JAXRSClientFactory and ResponseExceptionMapper Regards, Andrei. > -----Original Message----- > From: RAYAPROLU, SANJEEV [mailto:[email protected]] > Sent: Donnerstag, 15. Juni 2017 20:17 > To: [email protected] > Subject: CXF Client API - Implementing ResponseExceptionMapper on client > side for custom exception handling > > Hello, > > Problem Statement: Unable to implement custom client side exception handler > using Client (javax.ws.rs.client.Client) API, and @Provider class implementing > the ResponseExceptionMapper interface. > Questions: 1. Does Client API not support custom client side providers for > exception handling? 2. Any literature I looked up for this problem statement > uses JAXRSClientFactory implementation; I'm yet to find any using Client API > for > this scenario. Would I have to switch my implementation? 3. What is the > difference between Client API and JAXRSClientFactory implementations? > > I am working on a cxf Client API implementation in Java, and noticed that for > most http status codes above 300 cxf wraps the Response in either a > WebApplicationException or ProcessingException (depending upon the > response status code). The server in my case has a customized response body > indicating the actual reason for an http status code !200, like below (for > response code = 412): > > { > "requestError": { > "serviceException": { > "messageId": "SVC4120", > "text": "Invalid Request: Invalid Coupon Code." > } > } > } > > Unfortunately the WebApplicationException itself does not render this. Instead > the only message captured in the exception directly is a generic "412 > Precondition Failed". I can do something similar to below code snippet > (includes > Client API code snippet): > > 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); > } > } > I am looking to implement something cleaner, preferably using a custom > Exception handler that implements ResponseExceptionMapper<> interface. > From literature I noticed the only implementations of > ResponseExceptionMapper for custom client side exception handling are using > JAXRSClientFactory. My current implementation however uses the Client API > (code snippet below). From a design aspect I will modify this to have a > separate > CustomExceptionMapper class that would be the Provider only for Exception > cases, but I do not see why this Custom class is registered as a Provider > (works > for 200 status codes as MBR, and the MBW works always) but does not work > for exception cases. > > @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); > } > } > > > Question: I'm trying to figure out what is done wrong here; if Client API does > not support custom client side exception handling for any reason? What is the > difference between Client API and JAXRSClientFactory implementations? > > Any help appreciated. Thanks. > > Sanjeev
