Close

Servlet - Applying Filter based on DispatcherType

[Updated: Mar 8, 2018, Created: Mar 8, 2018]

A DispatcherType can be associated with a Java Servlet Filter to limit its scope. From ServletRequest.getDispatcherType() API doc:

The dispatcher type of a request is used by the container to select the filters that need to be applied to the request: Only filters with matching dispatcher type and url patterns will be applied.

The initial dispatcher type of a request is defined as DispatcherType.REQUEST. The dispatcher type of a request dispatched via RequestDispatcher.forward(ServletRequest, ServletResponse) or RequestDispatcher.include(ServletRequest, ServletResponse) is given as DispatcherType.FORWARD or DispatcherType.INCLUDE, respectively, while the dispatcher type of an asynchronous request dispatched via one of the AsyncContext.dispatch() methods is given as DispatcherType.ASYNC. Finally, the dispatcher type of a request dispatched to an error page by the container's error handling mechanism is given as DispatcherType.ERROR.

Example

In this example, we will create a Filter which will only be invoked for DispatcherType.ERROR.

A Servlet

@WebServlet(name = "currencyRateServlet", urlPatterns = {"/app/*"})
public class AppServlet extends HttpServlet {

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
          throws ServletException, IOException {
      PrintWriter writer = resp.getWriter();
      DispatcherType dispatcherType = req.getDispatcherType();
      String requestURI = req.getRequestURI();
      writer.write(String.format("response at %s, DispatcherType: %s%n", requestURI, dispatcherType));
      if (requestURI.endsWith("test")) {
          writer.println("AppServlet response at: " + requestURI);
      } else {
          int i = 10 / 0;//throwing exception
      }
  }
}

As seen above, our AppServlet can throw an exception, so let's create an error mapping in web.xml:

src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd" version="3.1">

    <error-page>
        <location>/error-handlers/default-error-handler</location>
    </error-page>

</web-app>

Also check out Servlet Error Handling tutorial.

The error handler Servlet

@WebServlet(name = "errorHandlerServlet",
      urlPatterns = {"/error-handlers/default-error-handler"})
public class ErrorHandlerServlet extends HttpServlet {

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
          throws ServletException, IOException {
      PrintWriter writer = resp.getWriter();
      writer.println("Error Handler Servlet:");
      resp.getWriter().printf("dispatcherType: %s%n", req.getDispatcherType());
  }
}

The Filter

@WebFilter(filterName = "errorFilter",
      urlPatterns = "/*",
      dispatcherTypes = {DispatcherType.ERROR})
public class ErrorFilter implements Filter {

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
  }

  @Override
  public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
          throws IOException, ServletException {
      chain.doFilter(req, resp);
      PrintWriter writer = resp.getWriter();
      writer.println("In the filter:");
      Exception exception = (Exception) req.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
      writer.printf("exception: %s%n", exception);
      Integer code = (Integer) req.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
      writer.printf("status_code: %s%n", code);
      String requestUri = (String) req.getAttribute(RequestDispatcher.ERROR_REQUEST_URI);
      resp.getWriter().printf("request_uri: %s%n", requestUri);
      resp.getWriter().printf("dispatcherType: %s%n", req.getDispatcherType());
  }

  @Override
  public void destroy() {
  }
}

To try examples, run embedded tomcat (configured in pom.xml of example project below):

mvn tomcat7:run-war

Output

As seen above, our filter did not invoke. It will only be invoked if there's an error.

Let's try an URI not mapped to our app servlet:

Notes

Specifying DispatcherType in web.xml

In case if we are doing xml based configuration rather than annotation one:

....
 <filter-mapping>
   <filter-name>errorFilter</filter-name>
   <url-pattern>/*</url-pattern>
   <dispatcher>ERROR</dispatcher>
 </filter-mapping>
...

We can use multiple <dispatcher> within <filter-mapping>.

Setting DispatcherType during dynamic filter registration

@WebListener
public class MyContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        FilterRegistration.Dynamic fr = sce.getServletContext()
                                           .addFilter("errorFilter", ErrorFilter.class);
        EnumSet<DispatcherType> dts = EnumSet.of(DispatcherType.ERROR);
        fr.addMappingForUrlPatterns(dts, false, "/*");
    }
   .....
}

Check out Servlet Dynamic registration tutorial and other example as well.

Example Project

Dependencies and Technologies Used:

  • javax.servlet-api 3.1.0 Java Servlet API
  • JDK 1.8
  • Maven 3.3.9

DispatcherType Example Select All Download
  • servlet-dispatcher-type-example
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • ErrorFilter.java
          • webapp
            • WEB-INF

    See Also