You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by liw <pa...@yahoo.com> on 2009/09/18 21:15:06 UTC

How to handle exception from cxf interceptors?

Hi,

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. JAXRSInInterceptor).

For example, if I use an invalid request url (e.g no matched path or
method), WebApplicationException is thrown by
JAXRSInInterceptor.processRequest() method.  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? 

{
      result: {
          code: "E2002"
          message: "Invalid Request"
      }
}



Here is the code snippet for our exception mapper provider and it works for
the exception from application code.

Code Snippet
========================
public Response toResponse(Exception exception) {
		Response response = null;
		StdRuntimeException rootCause = null;
	
		if (exception instanceof StdRuntimeException) {
			rootCause = (StdRuntimeException) exception;
		}
		else if (exception.getCause() != null && exception.getCause() instanceof
StdRuntimeException) {
			rootCause = (StdRuntimeException) exception.getCause();
		} 
		//for WebApplicationException thrown in API implementation
		else if (exception instanceof WebApplicationException) {
			response = ((WebApplicationException)exception).getResponse();
		} 
		
		if (rootCause != null) {
			String errorCode = null;
			String errorMessage = null;
			ErrorHandler  errorHandler = (ErrorHandler)
BeanFactory.getBeanInstance(AppConstants.BEAN_WSMT_ERROR_HANDLER);
			try {
				StdErrorMessageAdapter messageAdapter = (StdErrorMessageAdapter)
errorHandler.handleException(rootCause);
				Map errorDetails = messageAdapter.getErrorDetails();
				for (Map.Entry<String, List<String>> me : ((Map<String, List<String>>)
errorDetails).entrySet()) {
					String key = me.getKey();
					if (key.equals(AppConstants.PARAM_CODE)) {
						errorCode = me.getValue().get(0);
					} else if (key.equals(AppConstants.PARAM_MSG)) {
						errorMessage = me.getValue().get(0);
					}
				}
	        }catch (Exception e) {
	        	log.debug("Exception during handling the exception. This should
not happen", e);
	        }
	        
			Error error = new Error();
			error.setCode(errorCode);
			error.setMessage(errorMessage);
			
			ResponseBuilder rb =
Response.status(Response.Status.INTERNAL_SERVER_ERROR);
			rb.type(MediaType.APPLICATION_JSON);
			rb.entity(error);
			response = rb.build();
		}
		return response;
	}

Thanks in advance,

Li


-- 
View this message in context: http://www.nabble.com/How-to-handle-exception-from-cxf-interceptors--tp25514049p25514049.html
Sent from the cxf-user mailing list archive at Nabble.com.


RE: How to handle exception from cxf interceptors?

Posted by Sergey Beryozkin <se...@iona.com>.
Hi

I'm sorry for a late response.

This code line in JAXRSInInterceptor :

message.getExchange().put(Response.class, excResponse);

will result in a JAXRSInvoker returning without invoking a service and this
(exception mapper) response will be eventually handled by a
JAXRSOutInterceptor. 

So if you update your mapper to return a custom response in case of
WebApplicationException then it should work as expected

let me know please if you still have problems with customizing a
WebApplicationException response when it's thrown from JAXRSInInterceptor

cheers, Sergey


liw wrote:
> 
> Hi Sergey,
> 
> I can change my exception handler to create a custom response, but the
> problem here is that it doesn't even return the response to the user this
> in this case.
> 
> Here is the code snippet from JAXRSInIntercepter. It users the exception
> handler to convert the fault to response, but after that, it puts the
> response to the exchange. It then continues to invoke the next
> InInterceptor, which in our case there is a RuntimeException thrown by our
> custom InIntercepter. It then calls the fault interceptor handles the
> fault. Since our custom fault intercepter only handles SoapMessage, it
> returns a xml error response.
> 
> <ns1:XMLFault>
> <ns1:faultstring>
>    Endpoint method NULL
> </ns1:faultstring>
> </ns1:XMLFault>
> 
> 
> Code Snippet from JAXRSInIntercepter
> ===========================
>  public void handleMessage(Message message) {
>         
>         try {
>             processRequest(message);
>         } catch (RuntimeException ex) {
>             Response excResponse = JAXRSUtils.convertFaultToResponse(ex,
> message);
>             if (excResponse == null) {
>                
> ProviderFactory.getInstance(message).clearThreadLocalProxies();
>                 throw ex;
>             }
>             message.getExchange().put(Response.class, excResponse);
>         }
>     }
> 
> 
> Code Snippet from our Custom FaultInterceptor
> ===================================
> 
> 
> public void handleMessage(Message message) throws Fault {
>         if(message==null ||message.getExchange()==null ||
> message.getContent(Exception.class) == null ) {
>             log.error("Error processing fault. Error context missing.");
>             throw new StdRuntimeException("Unknown Error has Occurred.");
>         }
>         
>         if (message instanceof SoapMessage) {
> 	
> 	        SoapMessage msg = (SoapMessage)message;
> 	        addHeader(msg, AppConstants.SID, AppUtils.getHostName());
> 	        addHeader(msg, AppConstants.STIME, new Date().toString());
> 	
> 	        Fault fault = (Fault)message.getContent(Exception.class);
> 	        Throwable rootCause = fault.getCause()!=null ? fault.getCause() :
> fault;
> 	        SoapFault sf = SoapFault.createFault(fault, msg.getVersion());
> 	        message.setContent(Exception.class, sf);
>                 . . .
>     
>         }
>     }
> 
> 
> 
> However, when an exception is thrown in the application code, the
> JAXRSInvoker.invoke() method converts the fault to response and returns a
> MessageContentsList. It marshals the response and return JSON response to
> user.
> 
> 
> code snippet from  JAXRSInvoker.invoke()
> =================================
> 
> catch (Fault ex) {
>             Response excResponse =
> JAXRSUtils.convertFaultToResponse(ex.getCause(), 
>                                                                     
> exchange.getInMessage());
>             if (excResponse == null) {
>                
> ProviderFactory.getInstance(exchange.getInMessage()).clearThreadLocalProxies();
>                 ClassResourceInfo criRoot =
>                    
> (ClassResourceInfo)exchange.get(JAXRSInInterceptor.ROOT_RESOURCE_CLASS);
>                 if (criRoot != null) {
>                     criRoot.clearThreadLocalProxies();
>                 }
>                 throw ex;
>             }
>             return new MessageContentsList(excResponse); 
> 
> 
> In the case of exception happens from interceptors, is there any way that
> we can return the response object back to user instead of invoking with
> the next interceptor?
> 
> is there any way we can enhance our existing fault interceptor and return
> a JSON response back to user?
> 
> Thanks a lot,
> 
> Li
> 
> 
> 
> Sergey Beryozkin-2 wrote:
>> 
>> Hi
>> 
>> Your exception handler recognizes that a WebApplicationException has
>> been thrown but the code block which creates a custom response is
>> skipped in such cases.
>> You may want to check the status code in such cases and if it's 404 then
>> also create a custom response.
>> 
>> There're few more options.
>> One option is to rethrow the WebApplicationException exception and let
>> it go to the container, it will be wrapped in a ServletException.
>> Another one is to rethrow but disable the propagation and register a
>> custom CXF OutFault interceptor. But hopefully updating your handler
>> will make a difference
>> 
>> Let me know please if you can make it work
>> Cheers, Sergey  
>> 
>> -----Original Message-----
>> From: liw [mailto:pattiewang@yahoo.com] 
>> Sent: 18 September 2009 20:15
>> To: users@cxf.apache.org
>> Subject: How to handle exception from cxf interceptors?
>> 
>> 
>> Hi,
>> 
>> 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. JAXRSInInterceptor).
>> 
>> For example, if I use an invalid request url (e.g no matched path or
>> method), WebApplicationException is thrown by
>> JAXRSInInterceptor.processRequest() method.  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? 
>> 
>> {
>>       result: {
>>           code: "E2002"
>>           message: "Invalid Request"
>>       }
>> }
>> 
>> 
>> 
>> Here is the code snippet for our exception mapper provider and it works
>> for
>> the exception from application code.
>> 
>> Code Snippet
>> ========================
>> public Response toResponse(Exception exception) {
>> 		Response response = null;
>> 		StdRuntimeException rootCause = null;
>> 	
>> 		if (exception instanceof StdRuntimeException) {
>> 			rootCause = (StdRuntimeException) exception;
>> 		}
>> 		else if (exception.getCause() != null &&
>> exception.getCause() instanceof
>> StdRuntimeException) {
>> 			rootCause = (StdRuntimeException)
>> exception.getCause();
>> 		} 
>> 		//for WebApplicationException thrown in API
>> implementation
>> 		else if (exception instanceof WebApplicationException) {
>> 			response =
>> ((WebApplicationException)exception).getResponse();
>> 		} 
>> 		
>> 		if (rootCause != null) {
>> 			String errorCode = null;
>> 			String errorMessage = null;
>> 			ErrorHandler  errorHandler = (ErrorHandler)
>> BeanFactory.getBeanInstance(AppConstants.BEAN_WSMT_ERROR_HANDLER);
>> 			try {
>> 				StdErrorMessageAdapter messageAdapter =
>> (StdErrorMessageAdapter)
>> errorHandler.handleException(rootCause);
>> 				Map errorDetails =
>> messageAdapter.getErrorDetails();
>> 				for (Map.Entry<String, List<String>> me
>> : ((Map<String, List<String>>)
>> errorDetails).entrySet()) {
>> 					String key = me.getKey();
>> 					if
>> (key.equals(AppConstants.PARAM_CODE)) {
>> 						errorCode =
>> me.getValue().get(0);
>> 					} else if
>> (key.equals(AppConstants.PARAM_MSG)) {
>> 						errorMessage =
>> me.getValue().get(0);
>> 					}
>> 				}
>> 	        }catch (Exception e) {
>> 	        	log.debug("Exception during handling the
>> exception. This should
>> not happen", e);
>> 	        }
>> 	        
>> 			Error error = new Error();
>> 			error.setCode(errorCode);
>> 			error.setMessage(errorMessage);
>> 			
>> 			ResponseBuilder rb =
>> Response.status(Response.Status.INTERNAL_SERVER_ERROR);
>> 			rb.type(MediaType.APPLICATION_JSON);
>> 			rb.entity(error);
>> 			response = rb.build();
>> 		}
>> 		return response;
>> 	}
>> 
>> Thanks in advance,
>> 
>> Li
>> 
>> 
>> -- 
>> View this message in context:
>> http://www.nabble.com/How-to-handle-exception-from-cxf-interceptors--tp2
>> 5514049p25514049.html
>> Sent from the cxf-user mailing list archive at Nabble.com.
>> 
>> 
>> 
> 
> 

-- 
View this message in context: http://www.nabble.com/How-to-handle-exception-from-cxf-interceptors--tp25514049p25530910.html
Sent from the cxf-user mailing list archive at Nabble.com.


RE: How to handle exception from cxf interceptors?

Posted by liw <pa...@yahoo.com>.
Hi Sergey,

I can change my exception handler to create a custom response, but the
problem here is that it doesn't even return the response to the user this in
this case.

Here is the code snippet from JAXRSInIntercepter. It users the exception
handler to convert the fault to response, but after that, it puts the
response to the exchange. It then continues to invoke the next
InInterceptor, which in our case there is a RuntimeException thrown by our
custom InIntercepter. It then calls the fault interceptor handles the fault.
Since our custom fault intercepter only handles SoapMessage, it returns a
xml error response.

<ns1:XMLFault>
<ns1:faultstring>
   Endpoint method NULL
</ns1:faultstring>
</ns1:XMLFault>


Code Snippet from JAXRSInIntercepter
===========================
 public void handleMessage(Message message) {
        
        try {
            processRequest(message);
        } catch (RuntimeException ex) {
            Response excResponse = JAXRSUtils.convertFaultToResponse(ex,
message);
            if (excResponse == null) {
               
ProviderFactory.getInstance(message).clearThreadLocalProxies();
                throw ex;
            }
            message.getExchange().put(Response.class, excResponse);
        }
    }


Code Snippet from our Custom FaultInterceptor
===================================


public void handleMessage(Message message) throws Fault {
        if(message==null ||message.getExchange()==null ||
message.getContent(Exception.class) == null ) {
            log.error("Error processing fault. Error context missing.");
            throw new StdRuntimeException("Unknown Error has Occurred.");
        }
        
        if (message instanceof SoapMessage) {
	
	        SoapMessage msg = (SoapMessage)message;
	        addHeader(msg, AppConstants.SID, AppUtils.getHostName());
	        addHeader(msg, AppConstants.STIME, new Date().toString());
	
	        Fault fault = (Fault)message.getContent(Exception.class);
	        Throwable rootCause = fault.getCause()!=null ? fault.getCause() :
fault;
	        SoapFault sf = SoapFault.createFault(fault, msg.getVersion());
	        message.setContent(Exception.class, sf);
                . . .
    
        }
    }



However, when an exception is thrown in the application code, the
JAXRSInvoker.invoke() method converts the fault to response and returns a
MessageContentsList. It marshals the response and return JSON response to
user.


code snippet from  JAXRSInvoker.invoke()
=================================

catch (Fault ex) {
            Response excResponse =
JAXRSUtils.convertFaultToResponse(ex.getCause(), 
                                                                    
exchange.getInMessage());
            if (excResponse == null) {
               
ProviderFactory.getInstance(exchange.getInMessage()).clearThreadLocalProxies();
                ClassResourceInfo criRoot =
                   
(ClassResourceInfo)exchange.get(JAXRSInInterceptor.ROOT_RESOURCE_CLASS);
                if (criRoot != null) {
                    criRoot.clearThreadLocalProxies();
                }
                throw ex;
            }
            return new MessageContentsList(excResponse); 


In the case of exception happens from interceptors, is there any way that we
can return the response object back to user instead of invoking with the
next interceptor?

is there any way we can enhance our existing fault interceptor and return a
JSON response back to user?

Thanks a lot,

Li



Sergey Beryozkin-2 wrote:
> 
> Hi
> 
> Your exception handler recognizes that a WebApplicationException has
> been thrown but the code block which creates a custom response is
> skipped in such cases.
> You may want to check the status code in such cases and if it's 404 then
> also create a custom response.
> 
> There're few more options.
> One option is to rethrow the WebApplicationException exception and let
> it go to the container, it will be wrapped in a ServletException.
> Another one is to rethrow but disable the propagation and register a
> custom CXF OutFault interceptor. But hopefully updating your handler
> will make a difference
> 
> Let me know please if you can make it work
> Cheers, Sergey  
> 
> -----Original Message-----
> From: liw [mailto:pattiewang@yahoo.com] 
> Sent: 18 September 2009 20:15
> To: users@cxf.apache.org
> Subject: How to handle exception from cxf interceptors?
> 
> 
> Hi,
> 
> 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. JAXRSInInterceptor).
> 
> For example, if I use an invalid request url (e.g no matched path or
> method), WebApplicationException is thrown by
> JAXRSInInterceptor.processRequest() method.  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? 
> 
> {
>       result: {
>           code: "E2002"
>           message: "Invalid Request"
>       }
> }
> 
> 
> 
> Here is the code snippet for our exception mapper provider and it works
> for
> the exception from application code.
> 
> Code Snippet
> ========================
> public Response toResponse(Exception exception) {
> 		Response response = null;
> 		StdRuntimeException rootCause = null;
> 	
> 		if (exception instanceof StdRuntimeException) {
> 			rootCause = (StdRuntimeException) exception;
> 		}
> 		else if (exception.getCause() != null &&
> exception.getCause() instanceof
> StdRuntimeException) {
> 			rootCause = (StdRuntimeException)
> exception.getCause();
> 		} 
> 		//for WebApplicationException thrown in API
> implementation
> 		else if (exception instanceof WebApplicationException) {
> 			response =
> ((WebApplicationException)exception).getResponse();
> 		} 
> 		
> 		if (rootCause != null) {
> 			String errorCode = null;
> 			String errorMessage = null;
> 			ErrorHandler  errorHandler = (ErrorHandler)
> BeanFactory.getBeanInstance(AppConstants.BEAN_WSMT_ERROR_HANDLER);
> 			try {
> 				StdErrorMessageAdapter messageAdapter =
> (StdErrorMessageAdapter)
> errorHandler.handleException(rootCause);
> 				Map errorDetails =
> messageAdapter.getErrorDetails();
> 				for (Map.Entry<String, List<String>> me
> : ((Map<String, List<String>>)
> errorDetails).entrySet()) {
> 					String key = me.getKey();
> 					if
> (key.equals(AppConstants.PARAM_CODE)) {
> 						errorCode =
> me.getValue().get(0);
> 					} else if
> (key.equals(AppConstants.PARAM_MSG)) {
> 						errorMessage =
> me.getValue().get(0);
> 					}
> 				}
> 	        }catch (Exception e) {
> 	        	log.debug("Exception during handling the
> exception. This should
> not happen", e);
> 	        }
> 	        
> 			Error error = new Error();
> 			error.setCode(errorCode);
> 			error.setMessage(errorMessage);
> 			
> 			ResponseBuilder rb =
> Response.status(Response.Status.INTERNAL_SERVER_ERROR);
> 			rb.type(MediaType.APPLICATION_JSON);
> 			rb.entity(error);
> 			response = rb.build();
> 		}
> 		return response;
> 	}
> 
> Thanks in advance,
> 
> Li
> 
> 
> -- 
> View this message in context:
> http://www.nabble.com/How-to-handle-exception-from-cxf-interceptors--tp2
> 5514049p25514049.html
> Sent from the cxf-user mailing list archive at Nabble.com.
> 
> 
> 

-- 
View this message in context: http://www.nabble.com/How-to-handle-exception-from-cxf-interceptors--tp25514049p25515718.html
Sent from the cxf-user mailing list archive at Nabble.com.


RE: How to handle exception from cxf interceptors?

Posted by Sergey Beryozkin <sb...@progress.com>.
Hi

Your exception handler recognizes that a WebApplicationException has
been thrown but the code block which creates a custom response is
skipped in such cases.
You may want to check the status code in such cases and if it's 404 then
also create a custom response.

There're few more options.
One option is to rethrow the WebApplicationException exception and let
it go to the container, it will be wrapped in a ServletException.
Another one is to rethrow but disable the propagation and register a
custom CXF OutFault interceptor. But hopefully updating your handler
will make a difference

Let me know please if you can make it work
Cheers, Sergey  

-----Original Message-----
From: liw [mailto:pattiewang@yahoo.com] 
Sent: 18 September 2009 20:15
To: users@cxf.apache.org
Subject: How to handle exception from cxf interceptors?


Hi,

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. JAXRSInInterceptor).

For example, if I use an invalid request url (e.g no matched path or
method), WebApplicationException is thrown by
JAXRSInInterceptor.processRequest() method.  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? 

{
      result: {
          code: "E2002"
          message: "Invalid Request"
      }
}



Here is the code snippet for our exception mapper provider and it works
for
the exception from application code.

Code Snippet
========================
public Response toResponse(Exception exception) {
		Response response = null;
		StdRuntimeException rootCause = null;
	
		if (exception instanceof StdRuntimeException) {
			rootCause = (StdRuntimeException) exception;
		}
		else if (exception.getCause() != null &&
exception.getCause() instanceof
StdRuntimeException) {
			rootCause = (StdRuntimeException)
exception.getCause();
		} 
		//for WebApplicationException thrown in API
implementation
		else if (exception instanceof WebApplicationException) {
			response =
((WebApplicationException)exception).getResponse();
		} 
		
		if (rootCause != null) {
			String errorCode = null;
			String errorMessage = null;
			ErrorHandler  errorHandler = (ErrorHandler)
BeanFactory.getBeanInstance(AppConstants.BEAN_WSMT_ERROR_HANDLER);
			try {
				StdErrorMessageAdapter messageAdapter =
(StdErrorMessageAdapter)
errorHandler.handleException(rootCause);
				Map errorDetails =
messageAdapter.getErrorDetails();
				for (Map.Entry<String, List<String>> me
: ((Map<String, List<String>>)
errorDetails).entrySet()) {
					String key = me.getKey();
					if
(key.equals(AppConstants.PARAM_CODE)) {
						errorCode =
me.getValue().get(0);
					} else if
(key.equals(AppConstants.PARAM_MSG)) {
						errorMessage =
me.getValue().get(0);
					}
				}
	        }catch (Exception e) {
	        	log.debug("Exception during handling the
exception. This should
not happen", e);
	        }
	        
			Error error = new Error();
			error.setCode(errorCode);
			error.setMessage(errorMessage);
			
			ResponseBuilder rb =
Response.status(Response.Status.INTERNAL_SERVER_ERROR);
			rb.type(MediaType.APPLICATION_JSON);
			rb.entity(error);
			response = rb.build();
		}
		return response;
	}

Thanks in advance,

Li


-- 
View this message in context:
http://www.nabble.com/How-to-handle-exception-from-cxf-interceptors--tp2
5514049p25514049.html
Sent from the cxf-user mailing list archive at Nabble.com.