Skip to end of metadata
Go to start of metadata

Error handling for MyFaces Core 2.0 and later versions

Since JSF 2.0, it is possible to provide a custom javax.faces.context.ExceptionHandler or javax.faces.context.ExceptionHandlerWrapper implementation to deal with exceptions. To do that, just create your custom class, an factory that wrap/override it and add the following into your faces-config.xml:

faces-config.xml

This is an example of an ExceptionHandlerFactory, from myfaces code:

ExceptionHandlerFactoryImpl.java

If you need a wrapper:

ExceptionHandlerFactoryImpl.java

The most important method to override is ExceptionHandler.handle().

MyFacesExceptionHandlerWrapperImpl.java

Take a look at MyFaces Core source code, to know in detail how ExceptionHandler implementations works.

MyFaces ExceptionHandler

MyFaces Core provide a custom ExceptionHandler to deal with exceptions and provide detailed information about it. Since 2.0.8/2.1.2 this is disabled on Production environments unless it enabled on web.xml file. Don't forget to provide your custom error page in this scenario, to prevent show more information than necessary.

Provide an error page

The default ExceptionHandler in Production stage or when myfaces error handling is disabled just throw an exception. So you can still setup an error page adding something like this in your web.xml file:

Error handling for MyFaces Core 1.2 and earlier versions

MyFaces, from version 1.2.1 and 1.1.6, includes automatic error-handling for the full JSF-Lifecycle (taken over mostly from Facelets, with a few adoptions and additions). So for most projects during development, you will have exactly what you want with these new error-handling possibilities.

If this is not what you want, though, you can always disable or modify this error-handling with the following parameters:

If you do this, you can now read on to get to general ways of handling server-errors.

Server errors such as HTTP 500 can occur for a number of reasons such as uncaught exceptions, missing JSFs or backing beans, bad URL and the list goes on. While we hope these only occur during development it is important to plan to catch and deal with these errors gracefully when running live with multiple users.

Several approaches have been discussed on the mailing list:

Use default handler

Myfaces has a default error handler (class javax.faces.webapp._ErrorPageWriter) that uses a jsp template file (META-INF/rsc/myfaces-dev-error.xml and META-INF/rsc/myfaces-dev-debug.xml) to handle errors.

For define a custom template file:

Use sandbox org.apache.myfaces.tomahawk.util.ErrorRedirectJSFPageHandler

This handler uses myfaces error handling feature, redirecting to a jsf page when an error occurs.

An example jsf page for redirect can be found at http://issues.apache.org/jira/browse/TOMAHAWK-1297

This class is set as a config-parameter org.apache.myfaces.ERROR_HANDLER
available on myfaces core jsf. (This does not work with RI)

The idea is extends myfaces error handling feature, making possible to redirect
to a jsf page when an error occur, using navigation rules.

If this handler is not able to handle the error, an alternate error handler
could be set in the config-parameter org.apache.myfaces.ERROR_REDIRECT_ALTERNATE_HANDLER

The info of the error in the jsf page can be found using:

Using servlets

Mert Caliskan (http://www.jroller.com/page/mert?entry=handling_errors_with_an_errror) describes an approach which wraps the JSF servlet with a new servlet which delegates to the faces servlet but handles uncaught exceptions allowing the developer to redirect to a custom error page.

Andrea Paternesi has refined this technique for MyFaces as described here:
[http://patton-prog-tips.blogspot.com/2008/10/myfaces-handling-viewexpiredexception.html]

With JSF

Another approach is described in the book 'Core Server Faces' which uses the servlet engine to catch the error and delegate to a JSF error page. While not as elegant as the first approach this method has several advantages for some users

1 It uses a standard JSP approach and framework<<BR>>
2 It does not require custom servlets<<BR>>
3 It can easily be customized/changed by simply changing the error handler definition in the web.xml<<BR>>

To implement this method perform the following steps

1 define an error handling web page in web.xml

2 Create the error handler display. Due to a problem with the JSF 1.1 specification, the error handling page cannot use a <f:view> but must use a subview.

3 Create a backing bean in request scope which can process the error. (don't forget to register it on faces-config.xml)

ErrorDisplay.java

Also have a look at our ExceptionUtils class. It encapsulates the way how to get the real root cause

1 get a list of all exceptions - using getRootCause if available or getCause<<BR>>
2 get the initial exception<<BR>>
3 get the first exception with an message starting with the initial exception

So the new fillStackTrace become

In the backing bean we construct a message which informs the user that something we didnt't plan for has happened with directions on who to call, what to do etc. We don't really care if they actually do cut-and-paste the error and email it to us as it is also in Tomcat's logs but giving the user something to do and become part of resolving the problem is always a good idea (smile)

ViewExpiredException: No saved view state could be found for the view identifier

In some configurations, you might run into this problem exception with the error handling method shown above. This will happen if an error results in a forward, rather than redirect. The ''ViewHandler'' will call ''response.sendError()'' in case of an error, which will lookup your ''<error-page>'' declarations in ''web.xml'' and forward to the error url. If the error url is picked up by the ''FacesServlet'' (i.e. it's a JSF url), a new JSF lifecycle will be started. However, since this is a forward, the request object will still contain all of the request parameters, including ''"javax.faces.ViewState"'', which makes the request look like a postback to the ''ViewHandler''. Since it's a postback, the ''ViewHandler'' will expect a saved view, which is clearly not going to be there, since our ''viewId'' is now referencing the error page.

This problem can be solved by customizing the ''ViewHandler'' to use ''response.sendRedirect()'' instead of ''response.sendError()'', but that will mean that we can no longer use ''web.xml'' for specifying the error page mappings.

Another way to handle this would be to use an intermediate step by specifying a non-JSF URL as the error page and then somehow redirecting to the JSF error page. For example, for the 404 error code you could specify ''/error/404_redirect.html'':

This works, but requires you to hard code the context path.

The solution I ended up with involves a ''RedirectServlet'':

RedirectServlet.java

used like this in ''web.xml'':

With plain JSP

If you didn't require any JSF functionality in your JSP page it might be worth to consider using the following error.jsp

[http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/examples/simple/src/main/webapp/error.jsp?view=markup]

with this web.xml configuration

This reduces the number of technologies required to show the error page which might improve the availablity of this page (wink)

Custom error handler under Apache Geronimo JavaEE server

If you would use your own error handler (org.apache.myfaces.ERROR_REDIRECT_ALTERNATE_HANDLER) under Apache Geronimo, you must set properly your deployment plan (geronimo-web.xml usualy), otherwise you will have classloading problem of your class. By default the MyFaces classes are loaded to your classpath through dependencies at org.apache.geronimo.framework.jee-specs/CAR. This is OK for common cases, but if you instruct MyFaces to use your own error handler class, you get the error because MyFaces cannot find your class in calling class.forName(). Avoid this situation is quite simple - in your deployment plan specify dependencies on myfaces-api and myfaces-impl and then modify classloading via hidden-classes setting.

A fragment of your dependency plan would be like this:

This solution was tested under Apache Geronimo 2.1.3., but will probably be similar in other versions.