Search This Blog

Tuesday, September 21, 2010

JSF 2 Exception Handling

JSF 2 introduced ExceptionHandler as central point for handling unexpected Exceptions that are thrown during the Faces lifecycle.

To avoid silent exceptions that are not catched in application implement your ExceptionHandler and do what ever you want with exception.

1. Create your implementation of ExceptionHandler:
public class MyExceptionHandler extends ExceptionHandlerWrapper {

  private static Log log = LogFactory.getLog(MyExceptionHandler.class);
  private ExceptionHandler wrapped;

  public MyExceptionHandler(ExceptionHandler wrapped) {
    this.wrapped = wrapped;
  }

  @Override
  public ExceptionHandler getWrapped() {
    return wrapped;
  }

  @Override
  public void handle() throws FacesException {
    //Iterate over all unhandeled exceptions
    Iterator i = getUnhandledExceptionQueuedEvents().iterator();
    while (i.hasNext()) {
      ExceptionQueuedEvent event = i.next();
      ExceptionQueuedEventContext context =
        (ExceptionQueuedEventContext)event.getSource();

      //obtain throwable object
      Throwable t = context.getException();

      //here you do what ever you want with exception
      try{
      //log error
        log.error("Serious error happened!", t);
        //redirect to error view etc....  
      }finally{
        //after exception is handeled, remove it from queue
        i.remove();
      }
    }
    //let the parent handle the rest
    getWrapped().handle();
  }
}
2. Create your ExceptionHandlerFactory and call your ExceptionHandler:
public class MyExceptionHandlerFactory extends ExceptionHandlerFactory {

  private ExceptionHandlerFactory parent;

  // this injection handles jsf
  public MyExceptionHandlerFactory(ExceptionHandlerFactory parent) {
    this.parent = parent;
  }

  //create your own ExceptionHandler
  @Override
  public ExceptionHandler getExceptionHandler() {
    ExceptionHandler result =
        new MyExceptionHandler(parent.getExceptionHandler());
    return result;
  }
}
3. Register your exception handler factory in faces-config.xml:
<factory>
  <exception-handler-factory>
    test.MyExceptionHandlerFactory
  </exception-handler-factory>
</factory>

15 comments:

  1. Thanks dude. Just what I was searching for!

    ReplyDelete
  2. Thank you for this post!

    I'm new to JSF and I'm searching a way to redirect my exceptions to an exception page, where for example the message text is found.

    Is it a good idea to use an ExceptionHandler for this or is there a better way to access exception information?

    I already tried to redirect the user to an error page (<exception-type... in web.xml). The redirection works, but I don't know how to get the exception information.

    ReplyDelete
  3. I found a way to access information about the thrown Exception:

    FacesContext fc = FacesContext.getCurrentInstance();
    Map requestMap = fc.getExternalContext().getRequestMap();

    exception = (Throwable) requestMap.get("javax.servlet.error.exception");

    Now I can get the message, the stack trace, etc etc.

    Thanks again for this great post.

    ReplyDelete
  4. You could use the getRootCause() from the wrapped parent instead

    ReplyDelete
  5. the JSP error pages have a default "exception" object available to standard JSP:

    <% out.print(exception.getMessage()); %>

    ReplyDelete
  6. I was ferkeling with this and tried to get my Messages populated on my page; have you any ideas why they dont show up in the messages area...

    ...

    h:form id="messagesForm"
    div id="messagesArea"
    p:messages id="global_messages" showDetail="true" autoUpdate="true"
    div
    h:form

    ...
    Throwable eachException = eachExceptionQueuedEvent.next().getContext().getException();
    ...
    message = eachException.getMessage();
    ...
    FacesMessage faces_message = new FacesMessage(message); faces_message.setSeverity(FacesMessage.SEVERITY_ERROR);
    facesContext.addMessage(null, faces_message);

    ReplyDelete
    Replies
    1. messages are lost because of the redirect..try saving them in flash scope

      Delete
  7. This comment has been removed by the author.

    ReplyDelete
  8. Hi,

    getUnhandledExceptionQueuedEvents() method always returns an empty list in my case.

    Any ideas?

    ReplyDelete
  9. Hi, This is working partially for me, ExceptionHandler is invoke as I expected but I am trying to display certain kind of exceptions (BusinessException) as messages on the top of my page I mean as handled errors. I have the next code:
    public void handle() throws FacesException {
    //Iterate over all unhandeled exceptions
    Iterator i = getUnhandledExceptionQueuedEvents().iterator();
    while (i.hasNext()) {
    ExceptionQueuedEvent event = i.next();
    ExceptionQueuedEventContext context = (ExceptionQueuedEventContext)event.getSource();
    //obtain throwable object
    Throwable t = context.getException();
    Throwable cause = this.getInitCause(t);
    //here you do what ever you want with exception
    try{
    if(cause instanceof BusinessException){
    log.debug("This is a business Exception");
    log.debug("Business Error Key: "+cause.getMessage());
    String message = getBundle(ViewAppBean.DEFAULT_MESSAGE_BUNDLE, getLocale()).getString(cause.getMessage());
    getFacesContext().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null) );
    }
    //redirect to error view etc....
    }finally{
    //after exception is handeled, remove it from queue
    i.remove();
    }
    }

    //let the parent handle the rest
    getWrapped().handle();
    }
    I debugged and method is invoked and everything appears to be fine but I just get a blank page with no errors on server console, any idea?

    ReplyDelete
    Replies
    1. Hello Anonymous,

      I am trying to display messages in my page with getFacesContext() and new FacesMessage() .. from my handle method but my messages dont't show up in the messages area ?
      Have you resolve your problem

      Thanks

      Delete