CXF/ JAX-RS : Return Custom response from interceptor

cxf, exception, interceptor, java, jax-rs

Solution

I found a way to send a custom response from the interceptor but still can't figure out a way to call my CustomExceptionHandler from the interceptor

Code:

public void handleMessage(Message message) {

        MetadataMap<String, String> metadataMap = (MetadataMap<String, String>) message.get("jaxrs.template.parameters");

        if(null != metadataMap) {
            List<String> list = metadataMap.get("phoneNumber");
            if(null != list) {
                String phoneNumber = list.get(0);
                boolean result = validatePhoneNumber(phoneNumber);
                if(!result){
// Create a response object and set it in the message. 
// calling getExchange() will not call your service
                    Response response = Response
                .status(Response.Status.BAD_REQUEST)
                .entity(new ErrorDetail(Response.Status.BAD_REQUEST.getStatusCode(), Response.Status.BAD_REQUEST.toString()))
                .build();
        message.getExchange().put(Response.class, response);
// That's it
                }
            } else {
                Response response = Response
                .status(Response.Status.BAD_REQUEST)
                .entity(new ErrorDetail(Response.Status.BAD_REQUEST.getStatusCode(), Response.Status.BAD_REQUEST.toString()))
                .build();
        message.getExchange().put(Response.class, response);
            }
        } else {
            Response response = Response
                .status(Response.Status.BAD_REQUEST)
                .entity(new ErrorDetail(Response.Status.BAD_REQUEST.getStatusCode(), Response.Status.BAD_REQUEST.toString()))
                .build();
        message.getExchange().put(Response.class, response);
        }
    }

Problem

We need to return custom error code and error message when exception occurs during REST invocation. We have created a exception mapper provider, it works well for the exceptions from the application code. However, it doesn't work when exception occurs from the CXF code (e.g. form the CustomValidationInterceptor that I wrote). For example, if I request with invalid path parameter (e.g invalid phoneNumber). In this case, we need to return a custom error code and error message in JSON format, but it doesn't work even though we have a exception mapper provider created to handle WebApplicationException. Is there any way to handle exceptions from cxf interceptors and return response to user with something like the following? ``` { "errorDetail": { "errorCode": "404", "errorMessage": "Bad Request" } } ``` Code Snippet of my CustomValidationInterceptor : ``` public class CustomValidationInterceptor extends AbstractPhaseInterceptor<Message>{ public CustomValidationInterceptor() { super(Phase.PRE_INVOKE); // Put this interceptor in this phase } public void handleMessage(Message message) { MetadataMap<String, String> metadataMap = (MetadataMap<String, String>) message.get("jaxrs.template.parameters"); if(null != metadataMap) { List<String> list = metadataMap.get("phoneNumber"); if(null != list) { String phoneNumber = list.get(0); boolean result = validatePhoneNumber(phoneNumber); if(!result){ throw new TelusServiceException(Response.status(Response.Status.BAD_REQUEST).build(), 400, "phone number not valid"); } } else { throw new TelusServiceException(Response.status(Response.Status.BAD_REQUEST).build(), 400, "phone number not valid"); } } else { throw new TelusServiceException(Response.status(Response.Status.BAD_REQUEST).build(), 400, "phone number not valid"); } } public boolean validatePhoneNumber(String phoneNumber) { Pattern pattern = Pattern.compile("^[1-9]\\d{9}$"); Matcher matcher = pattern.matcher(phoneNumber); if (!matcher.matches()) { return false; } return true; } } ``` Code Snippet of my Custom Exception Mapper Provider ``` public class TelusExceptionHandler implements ExceptionMapper<TelusServiceException> { public Response toResponse(TelusServiceException exception) { return Response.status(exception.getErrorDetail().getErrorCode()).entity(exception.getErrorDetail()).build(); } } ``` Code Snippet of TelusServiceException ``` public class TelusServiceException extends WebApplicationException{ // constructors and other methods private ErrorDetail errorDetail = null; public ErrorDetail getErrorDetail() { return errorDetail; } public void setErrorDetail(ErrorDetail errorDetail) { this.errorDetail = errorDetail; } public TelusServiceException(Response response, int errorCode, String errorMessage) { super(response); errorDetail = new ErrorDetail(); errorDetail.setErrorCode(errorCode); errorDetail.setErrorMessage(errorMessage); } } ``` Code Snippet of ErrorDetail class ``` @XmlRootElement(name="errorDetail") public class ErrorDetail { private int errorCode; private String errorMessage; @XmlElement(name = "errorCode") public int getErrorCode() { return errorCode; } public void setErrorCode(int errorCode) { this.errorCode = errorCode; } @XmlElement(name = "errorMessage") public String getErrorMessage() { return errorMessage; } public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; } } ```

Original source

Related problems