JSF Global Exception Handler Factory Example
In this tutorial we show you how to create a Global Exception Handler Factory. We create a factory that extends the javax.faces.context.ExceptionHandlerFactory
. Here we can override the getExceptionHandler
and return a new CustomExceptionHandler
which will handle all the exceptions thrown by JSF.
Error Throwing Managed Bean
Here is a simple managed bean that’ll throw an error.
package com.memorynotfound.jsf;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
@ManagedBean
@RequestScoped
public class ErrorBean {
public void throwError(){
throw new RuntimeException("throwing new error");
}
}
Custom Exception Handler Factory
We create a factory that extends the javax.faces.context.ExceptionHandlerFactory
. Here we can override the getExceptionHandler
and return a new CustomExceptionHandler
which will handle all the exceptions thrown by JSF.
package com.memorynotfound.jsf;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerFactory;
public class CustomExceptionHandlerFactory extends ExceptionHandlerFactory {
private ExceptionHandlerFactory exceptionHandlerFactory;
public CustomExceptionHandlerFactory() {
}
public CustomExceptionHandlerFactory(ExceptionHandlerFactory exceptionHandlerFactory) {
this.exceptionHandlerFactory = exceptionHandlerFactory;
}
@Override
public ExceptionHandler getExceptionHandler() {
return new CustomExceptionHandler(exceptionHandlerFactory.getExceptionHandler());
}
}
Custom Exception Handler
This class extends from javax.faces.context.ExceptionHandlerWrapper
and intercepts all the exceptions thrown by JSF. In the handle()
method we access the thrown exceptions to appropriately handle them. In this case we add some information to the request scope in order to print them on a custom error page.
package com.memorynotfound.jsf;
import javax.faces.FacesException;
import javax.faces.application.NavigationHandler;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
public class CustomExceptionHandler extends ExceptionHandlerWrapper {
private ExceptionHandler exceptionHandler;
public CustomExceptionHandler(ExceptionHandler exceptionHandler) {
this.exceptionHandler = exceptionHandler;
}
@Override
public ExceptionHandler getWrapped() {
return exceptionHandler;
}
@Override
public void handle() throws FacesException {
final Iterator<ExceptionQueuedEvent> queue = getUnhandledExceptionQueuedEvents().iterator();
while (queue.hasNext()){
ExceptionQueuedEvent item = queue.next();
ExceptionQueuedEventContext exceptionQueuedEventContext = (ExceptionQueuedEventContext)item.getSource();
try {
Throwable throwable = exceptionQueuedEventContext.getException();
System.err.println("Exception: " + throwable.getMessage());
FacesContext context = FacesContext.getCurrentInstance();
Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
NavigationHandler nav = context.getApplication().getNavigationHandler();
requestMap.put("error-message", throwable.getMessage());
requestMap.put("error-stack", throwable.getStackTrace());
nav.handleNavigation(context, null, "/error");
context.renderResponse();
} finally {
queue.remove();
}
}
}
}
Registering The Custom Exception Handler Factory
We must tell JSF that we have a custom exception handler factory.
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd" version="2.2">
<factory>
<exception-handler-factory>com.memorynotfound.jsf.CustomExceptionHandlerFactory</exception-handler-factory>
</factory>
</faces-config>
Simple view to invoke the error
This error simple invokes the error by clicking on a button.
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:body>
<h2>JSF Global exception handler factory example</h2>
<h:form>
<h:commandButton value="throw an error" actionListener="#{errorBean.throwError}"/>
</h:form>
</h:body>
</html>
Custom Error Page
This page will read the information in the request scope and print it on the screen.
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h:body>
<h2>Error page</h2>
<h4>Error message</h4>
#{requestScope['error-message']}
<h4>Stack trace</h4>
<ul>
<ui:repeat value="#{requestScope['error-stack']}" var="stack">
<li>#{stack.className} - #{stack.methodName} - #{stack.fileName} (#{stack.lineNumber})</li>
</ui:repeat>
</ul>
</h:body>
</html>
Demo
URL: http://localhost:8081/jsf-global-exception-handling/index.xhtml
The outcome of the produced error.