0

we have a number of API servlets, each of which implements get/post methods which call a service layer. The service layer can throw 5 or 6 different exceptions.

In each of our servlets, we have a catch for each one to convert them into formatted json error responses.

Each time we write a new servlet to perform a function, we have to cust and past around 30 lines of code to handle these exceptions in the same way.

Is there a strategy to remove this duplication?

E.g. could we create a filter for all these servlets which handles the exceptions? I dont know if filters can catch exceptions from servlets.

Another option would be to have one servlet and use it to route (aka giant if statement). But its too late to rewrite all our servlet apis.

Any other suggestions?

John Little
  • 10,707
  • 19
  • 86
  • 158
  • `try {...} catch (SomeException e) {ExceptionUtils.handle(e, ...);}` – Johannes Kuhn Aug 15 '22 at 19:51
  • Does this help you? https://stackoverflow.com/questions/26801038/how-to-redirect-to-error-page-when-exception-occurs-from-servlet and https://www.digitalocean.com/community/tutorials/servlet-exception-and-error-handling-example-tutorial – rickz Aug 16 '22 at 04:26

1 Answers1

1

You should use filters for this behavior. (Protip: filters are an essential concept within Servlet, so you should invest time in it to learn its basics. They will help you with a lot of functionality and patterns. If you understand filters, then your question is easy to solve.)

To give you a short intro in filters: a filter is like a decoration over your servlet. Every other new filter, is another new decoration over the already existing filter. When a HTTP request comes in, it starts with the outer filter (top), which calls the next filter, which calls the next filter, and so on, until the Servlet is reached. The servlet generates HTML body, and return to the last called filter, which will return to the previous filters, and so on, until the top filter finishes, and the response is send back to the client. (This is the most common use-case for filters.) A single filter can be applied to multiple url-patterns and servlets, allowing code reuse.

Here is example using filters for exception handling:

public class ExceptionHandlingFilter implements Filter {
    public void init(FilterConfig config) {}
    public void destroy() {}

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        try {
            chain.doFilter(request, response);
        } catch (Exception ex) {
            System.out.println("I handle all your exceptions!");
        }
    }
}

Override the catch block with your exception handling code.

In your web.xml add:

<filter>
    <filter-name>ExceptionHandlingFilter</filter-name>
    <filter-class>com.example.demo.ExceptionHandlingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>ExceptionHandlingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Put this xml code before other filter-mapping definitions, so that it is the first filter in the filterChain, so that it is also able to catch exceptions thrown by other filters. (In case you prefer servlet annotations: you cannot define filter order using annotations, so if you have multiple filters, you'll need to define <filter-mapping> in web.xml anyway, otherwise the ExceptionHandlingFilter may skip exceptions thrown by other filters.)

Devabc
  • 4,782
  • 5
  • 27
  • 40
  • this is great. We use several filters, but I could not find info on how filters are affected by exceptions thrown in the servlet. We use Adobe AEM, which defines filters like this: @Component @SlingServletFilter( scope = { SlingServletFilterScope.REQUEST }, pattern = "/bin/api/.*", methods = { "GET", "POST" } ) @Designate(ocd = CorrelationLoggingFilter.Config.class) public class CorrelationLoggingFilter implements Filter {. However, I dont know how we change the order of the filters to ensure our one is at the top. – John Little Aug 18 '22 at 10:21
  • @John Little Filters use plain Java to call the next filter via doFilter(), which passes execution to the next filter, until it returns. So the outer/top filter will catch all exceptions, unless an exception is caught by a filter closer to the throw. The filter order is simply the order to `` as they are located in `web.xml`. I don't know Adobe AEM and Sling. It's possible that those frameworks catch the exception before my `ExceptionHandlingFilter` can catch it. If it doesnt work, also try to add `REQUEST`, `FORWARD`, `INCLUDE` and `ERROR` dispatchers to the `filter-mapping`. – Devabc Aug 18 '22 at 18:54
  • @John Little if that doesn't work, then you need to look into Adobe AEM or Sling to see if they catch the exception before `ExceptionHandlingFilter` can. But that's a different question than the main question about servlets. You should start by not letting your Servlets catch the exception, and let the exception bubble up to my `ExceptionHandlingFilter`. If the code requires the catch in order to compile, then you should catch it and then re-throw it packed in a RuntimeException, so that catching isn't required in the servlet. – Devabc Aug 18 '22 at 18:59