Sometimes using FacesMessage
s is not sufficient for reporting errors. For example, if you have a runtime error (invalid JSF mark-up or NullPointerExceptions) it is difficult to report them using FacesMessage
.
Creating a generic error page for JSF is similar to creating a generic error page for plain JSP applications. You'll need a configuration in web.xml to tell the servlet container to redirect errors to a given page. Then you'll need to create that page as well as a backing bean that can show you the stacktrace or error message.
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> ... markup for your web app ... <error-page> <error-code>500</error-code> <location>/Error.jsp</location> </error-page> </web-app>
With that we will get the servlet container to forward any Internal Server Errors (HTTP 500) to the page Error.jsp.
Okay, now we need to create a bean that will prepare the error message based on the exception that was thrown:
Error.java
package bigallan.beans; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Map; import javax.faces.context.FacesContext; import javax.servlet.ServletException; public class Error { public Error() {} public String getStackTrace() { // Get the current JSF context FacesContext context = FacesContext.getCurrentInstance(); Map requestMap = context.getExternalContext().getRequestMap(); // Fetch the exception Throwable ex = (Throwable) requestMap.get("javax.servlet.error.exception"); // Create a writer for keeping the stacktrace of the exception StringWriter writer = new StringWriter(); PrintWriter pw = new PrintWriter(writer); // Fill the stack trace into the write fillStackTrace(ex, pw); return writer.toString(); } /** * Write the stack trace from an exception into a writer. * * @param ex * Exception for which to get the stack trace * @param pw * PrintWriter to write the stack trace */ private void fillStackTrace(Throwable ex, PrintWriter pw) { if (null == ex) { return; } ex.printStackTrace(pw); // The first time fillStackTrace is called it will always be a ServletException if (ex instanceof ServletException) { Throwable cause = ((ServletException) ex).getRootCause(); if (null != cause) { pw.println("Root Cause:"); fillStackTrace(cause, pw); } } else { // Embedded cause inside the ServletException Throwable cause = ex.getCause(); if (null != cause) { pw.println("Cause:"); fillStackTrace(cause, pw); } } } }
Now that we have the Backing Bean we need to register it in faces-config.xml:
.. usual faces-config stuff .. <managed-bean> <managed-bean-name>Error</managed-bean-name> <managed-bean-class>bigallan.beans.Error</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean>
And lastly the JSP page (Error.jsp) displaying the error:
.. usual JSP header stuff .. <h:panelGrid> <h:outputText value="The follow error occured:" /> <h:inputTextarea style="width: 100%;" rows="20" readonly="true" value="#{Error.stackTrace}" /> </h:panelGrid>
That's all!
Enjoy.