1. Introduction

In this tutorial, we’re going to handle exceptions in a Jakarta EE Servlet application – in order to provide a graceful and expected outcome whenever an error happens.

2. Jakarta EE Servlet Exceptions

First, we’ll define a Servlet using the API annotations (have a look at the Servlets Intro for more details) with a default GET processor that will throw an exception:

@WebServlet(urlPatterns = "/randomError")
public class RandomErrorServlet extends HttpServlet {

    @Override
    protected void doGet(
      HttpServletRequest req, 
      HttpServletResponse resp) {
        throw new IllegalStateException("Random error");
    }
}

3. Default Error Handling

Let’s now simply deploy the application into our servlet container (we’re going to assume that the application runs under http://localhost:8080/javax-servlets).

When we access the address http://localhost:8080/javax-servlets/randomError, we’ll see the default servlet error handling in place:

servlet

Default error handling is provided by the servlet container and can be customized at a container or application level.

4. Custom Error Handling

We can define custom error handling using a web.xml file descriptor in which we can define the following types of policies:

  • Status code error handling – it allows us to map HTTP error codes (client and server) to a static HTML error page or an error handling servlet
  • Exception type error handling – it allows us to map exception types to static HTML error pages or an error handling servlet

4.1. Status Code Error Handling with an HTML Page

We can set up our custom error handling policy for HTTP 404 errors in the web.xml:

<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>
        <error-code>404</error-code>
        <location>/error-404.html</location> <!-- /src/main/webapp/error-404.html-->
    </error-page>

</web-app>

Now, access http://localhost:8080/javax-servlets/invalid.html from the browser – to get the static HTML error page.

4.2. Exception Type Error Handling with a Servlet

We can set up our custom error handling policy for java.lang.Exception in web.xml:

<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> 
        <exception-type>java.lang.Exception</exception-type> 
        <location>/errorHandler</location> 
    </error-page>
</web-app>

In ErrorHandlerServlet, we can access the error details using the error attributes provided in the request:

@WebServlet(urlPatterns = "/errorHandler")
public class ErrorHandlerServlet extends HttpServlet {

    @Override
    protected void doGet(
      HttpServletRequest req, 
      HttpServletResponse resp) throws IOException {
 
        resp.setContentType("text/html; charset=utf-8");
        try (PrintWriter writer = resp.getWriter()) {
            writer.write("<html><head><title>Error description</title></head><body>");
            writer.write("<h2>Error description</h2>");
            writer.write("<ul>");
            Arrays.asList(
              ERROR_STATUS_CODE, 
              ERROR_EXCEPTION_TYPE, 
              ERROR_MESSAGE)
              .forEach(e ->
                writer.write("<li>" + e + ":" + req.getAttribute(e) + " </li>")
            );
            writer.write("</ul>");
            writer.write("</html></body>");
        }
    }
}

Now, we can access http://localhost:8080/javax-servlets/randomError to see the custom error servlet working.

Note: Our exception type defined in the web.xml is too broad and we should specify all the exceptions we want to handle in more detail.

We can also use the container-provided servlet logger in our ErrorHandlerServlet component to log additional details:

Exception exception = (Exception) req.getAttribute(ERROR_EXCEPTION);
if (IllegalArgumentException.class.isInstance(exception)) {
    getServletContext()
      .log("Error on an application argument", exception);
}

It’s worth knowing what’s beyond the servlet-provided logging mechanisms, check the guide on slf4j for more details.

5. Conclusion

In this brief article, we have seen default error handling and specified custom error handling in a servlet application without adding external components nor libraries.

As always, you can find the source code over on Servlets tutorial repository.