Handling Exceptions on a WebApp

Hello everyone, how are you doing?

Let’s talk about how to handle exceptions in a web application? To learn how to create a web application, check this tutorial: Creating a WebServer. We will be using this tutorial to work with today.

Unexpected situations always going to happen and the worst part of it is when these problems go to the client’s screen, through messages that he won’t understand. When the client reads this kind of message he will begin to be suspicious about your software, and for every problem that happens he will blame your software (even when he gets disconnected from the internet).

PS.: In my articles, I usually don’t ask for specific software/technology but this time I will. Please, do not use the Internet Explorer (or Eclipses browser). In the end of this article I will tell you the reason that I’m asking this. This information about how IE handle exceptions, cost me 120 minutes (in my weekend), to find out the reason for today articles code does not work on Internet Explorer.

In our Servlet project (Creating a WebServer) when the user does not type a valid number, we use this piece of code to handle the situation:

try {
    // I know this is ugly, but in a future we can do some refactor and apply some OO and Design principles
    value1 = Integer.parseInt((String) req.getParameter("valor1"));
} catch (NumberFormatException e) {
    // Catching this execption in case some invalid value was sent
    value1 = 0;
    warning = "We got some bad value(like blank or non numerics values, we set 0 instead";
}

In this piece of code, when an error occurs a default value is given to the parameter, but what will happen when we cannot give a default value? There are some situations that exceptions happens and we have to inform the user about this problem. Also there are some exceptions that don’t reach our servlets; one of those exceptions would be when the user types a wrong http address he will receive a HTTP 404 error message on the screen. First let’s handle the 404 error and then an error caused by a wrong typing.

Let’s create a JSP that will handle the exception (inside the WebContent folder with “error.jsp” as its name):

<%@ page isErrorPage="true" language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title>Erro</title>;
    </head>
    <body>
        Ops, something happend! <br/>
        Error code: ${pageContext.errorData.statusCode}
    </body>
</html>

The isErrorPage parameter makes possible the access to the Exception object. The errorData object is created by the container inside the pageContext automatically. To finish, we need to chance the “web.xml” configuration so the container might be able to redirect our request to the error page.

We will have the following lines added to the web.xml file:

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

With this error tag we indicate to the container which kind of error is mapped and which destine it will have. When our user types an invalid address, he will be redirected to our error page.

To test, let’s start the container and then just type an invalid address directing it to our application:

http://localhost:8080/Servlet/ASD

There is not such servlet/url “ASD” mapped at the web.xml file; instead a HTTP 404 error, the user will see our error jsp. Can you see the benefits of that simple error-page configuration? The user will be redirected to that destination only when he types a wrong address, but we can also set for every kind of error to be redirected there, we just need to map the java.lang.Exception (we will see it soon).

Another option to handle exceptions is to redirect our error to a servlet where we can do several actions. Our sample code throws an exception when it try to sum the values without a valid data – like non numbers characters. At the first version of our software it gives a default value to the user when an exception was detected, but now, we will redirect the user to the error page where we might be able to tell him to type the value.

try {
    valor1 = Integer.parseInt((String) req.getParameter("valor1"));
} catch (NumberFormatException e) {
    throw new NumberFormatException("No numbers were typed");
}

Notice that now we are not setting a default value, but an exception is being thrown. It’s like we are telling to the container that something bad happened and the container should take care of it.

But we have not changed it on the web.xml file yet.

<servlet>
    <servlet-name>errorServlet</servlet-name>
    <servlet-class>com.ErrorController</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>errorServlet</servlet-name>
    <url-pattern>/errorServlet</url-pattern>
</servlet-mapping>
<error-page>
    <exception-type>java.lang.NumberFormatException</exception-type>
    <location>/errorServlet</location>
</error-page>

We have mapped the servlet that will handle the exception, and the described the error type that will be handled “NumberFormatException”. We could also set as the handled error type the “java.lang.Exception” so our servlet would capture every kind of error that would be raised at our application.

Let’s create now our servlet:

package com;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class ServletError
 */
public class ErrorController extends HttpServlet {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    public void doPost(HttpServletRequest req, HttpServletResponse res)    throws ServletException, IOException{
        Throwable throwable = (Throwable) req.getAttribute("javax.servlet.error.exception");
        Integer statusCode = (Integer) req.getAttribute("javax.servlet.error.status_code");

        req.setAttribute("errorType", throwable);
        req.setAttribute("statusCode", statusCode);

        RequestDispatcher requestDispatcher = req.getRequestDispatcher("/error.jsp");
        requestDispatcher.forward(req, res);
    }

    public void doGet(HttpServletRequest req, HttpServletResponse res)    throws ServletException, IOException{
        doPost(req, res);
    }
}

As bonus, what if we do a little change at our error.jsp? From now on our page will display the error type:

<%@ page isErrorPage="true" language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title>Erro</title>
    </head>
    <body>
        Ops, something happend! <br/>
        Error code: ${statusCode} <br/>
        The error type is: ${errorType.message}
        <br/>
    </body>
</html>

It was changed the “Error code” that we now are getting it from the Request, and we are accessing the “error type” from the error object that the container created for us.

Start the Tomcat and try to sum the values without any number and our container will understand that an exception happened and will redirect it to our servlet; the servlet will handle the exception and will redirect the request to the “error.jsp”. Using a servlet to handle our exceptions it’s a good idea because now we can log an error; send emails to the administrators, etc.

I will explain now why I’ve asked you to do not use the IE (Internet Explorer). When an exception happens, the container changes an attribute named SC_INTERNAL_SERVER_ERROR. The IE notices that this value has changed and take a default action by itself, ignoring all configuration that we have done. Try to run our application using the IE and you shall see how the IE handle the exception.
The first solution if would be change a configuration inside the IE:

Internet Options > Advanced > "Show Friendly HTTP Error Messages"

Uncheck this option, save, close the IE and open it again; try one more time to generate the exception. The IE will display the message that we wanted all the time. How we would ask to all of our customers to change this IE specific configuration? Imagine if a user is coming for the first time at our website and he typed the wrong address. How would he see the wrong message once the IE won’t display any of our messages?

Our second solution would be to change the response object statuses. When we change the responses statuses the IE thinks that there is no error, and will let the user see our “error.jsp”.

req.setAttribute("statusCode", statusCode);

res.setStatus(HttpServletResponse.SC_OK);
// We have to remove the exception from the request. If we do not remove the IE9 will not display out error page.
// IE9 will think that some error created a crash inside our application if we do not remove the exception from the request.
req.setAttribute("javax.servlet.error.exception", null);
req.setAttribute("javax.servlet.error.status_code", null);

RequestDispatcher requestDispatcher = req.getRequestDispatcher("/error.jsp");

This IE problem took me a good time of my weekend, and during the week I’ve talked a lot with my boss about it. Just after more research I could find some info about this.

I hope this post can help you. Any question? Just ask!

Leave a Comment