In this recipe we talk about the exception handling mechanism provided by JSF 2.0. You will see how to map exceptions to error pages in the web.xml
file, how to use a managed bean for extracting an exception from the request and build a String
from the stack trace, and how to customize the exception handling with a user-defined exception handler.
We start our recipe with the simplest solution for handling exceptions. It consists in mapping exception to error pages in the web.xml
descriptor. For start we add in web.xml
an entry for to define a JSF page as an error page (in our example, we define an error page named error.xhtml
, mapped to the java.lang.NumberFormatException
exception):
… <error-page> <exception-type>java.lang.NumberFormatException</exception-type> <location>/faces/error.xhtml</location> </error-page> …
Now, JSF keeps track of a set of values in the request that provide more details on the error page. Next you can see one of these values edited in error.xhtml
:
… User Error: #{requestScope['javax.servlet.error.message']} …
Now, we can test the previous example by throwing a java.lang.NumberFormatException
from a bean getter method, as shown next (when the error is thrown, the error.xhtml
error page is getting into action):
… private String number = "345s"; … public String getNumber() { try { Integer intnumber = Integer.valueOf(this.number); return String.valueOf(intnumber); } catch (NumberFormatException e) { throw new java.lang.NumberFormatException(e.getMessage()); } } public void setNumber(String number) { this.number = number; } …
Going further, we can write a managed bean for extracting the exception from the request and building a String
from the stack trace. You can see the action that does this job for us next:
… private String error = ""; … public String getError() { StringBuilder errorMessage = new StringBuilder(); FacesContext facesContext = FacesContext.getCurrentInstance(); Map<String, Object> map = facesContext.getExternalContext().getRequestMap(); Throwable throwable = (Throwable) map.get("javax.servlet.error.exception"); if (throwable != null) { errorMessage.append(throwable.getMessage()).append(" "); for (StackTraceElement element : throwable.getStackTrace()) { errorMessage.append(element).append(" "); } } this.error = errorMessage.toString(); return this.error; } …
To get the stack trace we use the following code in the error.xhtml
page:
… System Administrator Error: <br/> <h:outputText value="#{bean.error}"/> …
You can go even further and customize the exception handling. Any custom exception handler should be defined in faces-config.xml
, as in the folllowing example:
… <factory> <exception-handler-factory> exception.handler.CustomExceptionHandler </exception-handler-factory> </factory> …
In the custom exception handler you should override the handle
method to describe the behavior of your application in the case of a particular exception or set of exceptions. The prototype of this method is:
public void handle() throws FacesException { …//do your job here super.handle(); }
Basically, in all three cases described previously, the idea is the same. The exceptions are caught by the system and they are treated according to our desires. We can provide a simple error page, or we can get much deeper and exploit the exception's stack trace and create large logs with detailed information for users or for administrators.