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

jsf global exception handler factory

The outcome of the produced error.

jsf global exception handler factory

References

Download

You may also like...