Patan
Patan

Reputation: 17873

Custom exception mapping in web xml does not work

I have in my JSF 2.2 webapp a custom exception mapping in web.xml as below.

    <web-app 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_3_0.xsd"
    version="3.0">

    <display-name>Project</display-name>

    <!-- Welcome page -->
    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>

    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <session-config>
       <!-- some codes-->
    </session-config>

    <error-page>
        <exception-type>se.telenor.ocfd.service.api.exception.CustomNotFoundException</exception-type>
        <location>/not_found.xhtml</location>
    </error-page>

    <error-page>
        <error-code>404</error-code>
        <location>/404.xhtml</location>
    </error-page>

    <error-page>
        <location>/500.xhtml</location>
    </error-page>

    <error-page>
        <exception-type>javax.faces.application.ViewExpiredException</exception-type>
        <location>/session_timeout.xhtml</location>
    </error-page>

</web-app>

My Exception is

@ApplicationException
public class CustomNotFoundException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    public CustomNotFoundException(String message, Throwable cause) {
        super(message, cause);
    }

    public CustomNotFoundException(String message) {
        super(message);
    }
}

But it does not redirect me to not_found.xhtml page but instead always redirect to 500.xhtml page when the exception happens.

Can some one help me if any thing missing.

Upvotes: 1

Views: 1329

Answers (1)

BalusC
BalusC

Reputation: 1108567

That can happen if the exception is wrapped in another exception, e.g. FacesException or ELException, depending on who was the first to catch the actual exception and delegating it further to the caller in wrapped form. This would then only match an <error-page> with exactly the given <exception-type> of FacesException or ELException.

One way to solve it is creating a servlet filter which does something like below in doFilter() method:

try {
    chain.doFilter(request, response);
}
catch (ServletException e) {
    Throwable cause = e.getRootCause();

    if (cause instanceof FacesException || cause instanceof ELException) {
        throw new ServletException(cause.getCause()); // Unwrap and rethrow it.
    }
    else {
        throw e;
    }
}

Map it to the FacesServlet or perhaps application wide via an URL pattern of /*.

If you happen to use JSF utility library OmniFaces, a ready to use solution is available as FacesExceptionFilter.

Upvotes: 5

Related Questions