此帖子无法解决问题:ResponseExceptionMapper in cxf client。您会注意到我确实注册并注释了我的Provider,并且我尝试使用WebApplicationException而不是Exception / CustomException。
问题陈述:无法使用Client(javax.ws.rs.client.Client)API和实现ResponseExceptionMapper接口的@Provider类实现自定义客户端异常处理程序。
问题:
我正在使用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(尚未尝试过)。
任何帮助表示赞赏。感谢。