Today: April 18, 2024 1:31 pm
A collection of Software and Cloud patterns with a focus on the Enterprise

RESTful Java Servlet

For a recent project I found that a RESTful interface would be appropriate. My first inclination was to use Jersey (or one of the JAX-RS implementations available). The environment where this new REST API would deploy is still using Java 1.5. This became a major roadblock when I was found that none of the JAX-RS implementations provide support for the Java 1.5 virtual machine. This is not surprising since it’s few YEARS past EOSL (end of support life) for Java 1.5, but disappointing still the same.

After spending a day or so with the available frameworks, trying to get one of them to work in Java 1.5, I grew nervous that even if I did succeed, that puts my implementation squarely in a non-support region, even on the mailing lists. So I decided to see how close I could come to a simple, reliable RESTful interface using a plain old Java servlet (POJS?).

While I’m disappointed that I’m unable to leverage an existing, mature framework, I was happy with the outcome. Here are the details

HTTP Methods built in

To begin with, the servlet specification defines methods for the HTTP actions: GET, POST, PUT, DELETE, OPTIONS and HEAD.

Each of these methods receives a HttpServletRequest and HttpServletResponse object, which makes it easy to access the payload of the request and construct a response. Manipulation of return headers, payload content, response codes (200, 404, etc.) are all available directly through the HttpServletResponse object.

The only imports required to accomplish this were available in the standard Java environment, which relieved me of the need to worry about interoperability.

1
2
3
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

URI mapping

The next challenge was how to map RESTful URIs on to the methods in my servlet. At first glance, the conventional mapping done in the web.xml file wouldn’t be sufficient. The problem was with the extra parameters that were embedded in the URI. This goes just beyond what the mapping delineates in web.xml.

What I found was that a wildcard mapping and use of HttpServletRequest.getPathInfo() gave me all the information that I needed to complete the mapping. This is what my web.xml file looks like

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
	<display-name>testrestservlet</display-name>
	<servlet>
		<description></description>
		<display-name>TestRestServlet</display-name>
		<servlet-name>TestRestServlet</servlet-name>
		<servlet-class>com.danielwatrous.testrestservlet.TestRestServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>TestRestServlet</servlet-name>
		<url-pattern>/api/v1/*</url-pattern>
	</servlet-mapping>
</web-app>

The call I mentioned above, getPathInfo(), returns a string with everything that is in place of the asterisk (*) in my url-pattern above. This means that a URI of the form http://server/testrestservlet/api/vi/resource/id would return a string of “/resource/id” when getPathInfo() is called.

Avoid String Handling

I wanted to avoid messy string manipulation or analysis to parse out the details of this resource identification information. This ruled out any string splitting and checking for indexOf or startsWith.

Instead I wanted to be deliberate and reduce the possibility that a mis-mapping would slip through or that a future developer would misunderstand the exact nature of what to expect. For this reason I chose to use regular expressions. This provides a clear pattern of what my URI should look like, and it will be obvious to other developers. It also reduces the chances of a bad URI resulting in an inconsistent result.

I always use Kodos to develop regular expressions. After I got the regular expressions worked out for each class, I created an inner class inside the servlet that would help me map the URI to a specific request and give me access to the parameters embedded in the request URI. Here’s what that inner class looks like.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  private class RestRequest {
    // Accommodate two requests, one for all resources, another for a specific resource
    private Pattern regExAllPattern = Pattern.compile("/resource");
    private Pattern regExIdPattern = Pattern.compile("/resource/([0-9]*)");
 
    private Integer id;
 
    public RestRequest(String pathInfo) throws ServletException {
      // regex parse pathInfo
      Matcher matcher;
 
      // Check for ID case first, since the All pattern would also match
      matcher = regExIdPattern.matcher(pathInfo);
      if (matcher.find()) {
        id = Integer.parseInt(matcher.group(1));
        return;
      }
 
      matcher = regExAllPattern.matcher(pathInfo);
      if (matcher.find()) return;
 
      throw new ServletException("Invalid URI");
    }
 
    public Integer getId() {
      return id;
    }
 
    public void setId(Integer id) {
      this.id = id;
    }
  }

Now I’m set to override the methods for each of my HTTP actions.

The Servlet

At this point, creating the servlet is trivial. The mapping provides all path (resource) information to the servlet and our inner class is responsible to determining whether the URI makes sense for our application and to make that information available in a sensible way for processing of the request in the action methods. Here’s what I came up with:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package com.danielwatrous.testrestservlet;
 
import java.io.IOException;
import java.io.PrintWriter;
 
import java.util.regex.Pattern;
import java.util.regex.Matcher;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class TestRestServlet extends HttpServlet {
 
  private class RestRequest {
    // Accommodate two requests, one for all resources, another for a specific resource
    private Pattern regExAllPattern = Pattern.compile("/resource");
    private Pattern regExIdPattern = Pattern.compile("/resource/([0-9]*)");
 
    private Integer id;
 
    public RestRequest(String pathInfo) throws ServletException {
      // regex parse pathInfo
      Matcher matcher;
 
      // Check for ID case first, since the All pattern would also match
      matcher = regExIdPattern.matcher(pathInfo);
      if (matcher.find()) {
        id = Integer.parseInt(matcher.group(1));
        return;
      }
 
      matcher = regExAllPattern.matcher(pathInfo);
      if (matcher.find()) return;
 
      throw new ServletException("Invalid URI");
    }
 
    public Integer getId() {
      return id;
    }
 
    public void setId(Integer id) {
      this.id = id;
    }
  }
 
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    PrintWriter out = response.getWriter();
 
    out.println("GET request handling");
    out.println(request.getPathInfo());
    out.println(request.getParameterMap());
    try {
      RestRequest resourceValues = new RestRequest(request.getPathInfo());
      out.println(resourceValues.getId());
    } catch (ServletException e) {
      response.setStatus(400);
      response.resetBuffer();
      e.printStackTrace();
      out.println(e.toString());
    }
    out.close();
  }
 
  // implement remaining HTTP actions here
  ... 
 
}

Conclusion

This turned out to be a clear enough way to capture REST like URIs and map those onto a servlet for processing. Regular expressions provide for reliable and clear access to resource details and should be easy for future developers to quickly understand and extend.

In my next article, I’ll show you how I extend this servlet using the Jackson JSON library and a helper object to serialize and deserialize JSON payloads in RESTful requests.

Comments

  1. Well done. I was hoping there was an easy way to do this using servlets without having to rely on a framework. I like how you can just hand off to another servlet after the routing has been worked out usings the regex’s.
    Thanks for the writeup.

  2. I was using UUIDs so this is what I done to match the ID… thanks great code here

    matcher = regExIdPattern.matcher(pathInfo);
    if (matcher.find()) {
    id = UUID.fromString(pathInfo.substring(1));
    return;
    }

  3. So I am not sure I follow how this is RESTful. You capture a GET request. REST is all about utilizing protocols to indicate actions. For REST you need GET and POST, which are trivial to support in Servlets. What about PUT and DELETE? I came upon this article seeing if there was a way to do REST with java servlets. I still don’t see that.

    Are you simply doing some url parsing to load a resource in response to a GET? If so, I would not call this a RESTful Java Servlet.

    • Hi xgeoff,

      REST supports all the HTTP methods, like GET, POST, PUT, DELETE, HEADER, OPTIONS… If you want to handle any of those, you would use the servlet methods doPost, doPut, doDelete, etc. However, those are a bit beside the point of this post.

      First off, if you’re going to build a REST client in Java, I would start with Jersey, like I mention at the beginning of the post. If, like me, you’re stuck with a Java 5 environment, then you already know that Jersey support only reaches back as far as Java 6, so you have to use a basic servlet and build in the functionality you need.

      The point of this post is to show a clean way of building in URI parsing and request handling.

    • By the way, this article goes a step further and shows you how to handle JSON within the Servlet.

      http://software.danielwatrous.com/restful-java-servlet-serializing-tofrom-json-with-jackson/

  4. […] to apply the REST Architecture. You have to look more around this subject, here is some reading: RESTful Java Servlet | Daniel Watrous on Software Engineering Representational state transfer – Wikipedia, the free encyclopedia Regards, Reply […]

  5. Thank you, Daniel! You post helped me a lot!

  6. I have a requirement, where in we want to integrate two different softwares. Software1 will send a HTTP Post message (stuffed inside hidden html param) to the Software 2, which will then do some processing on it. Since the size of the xml will be more than 2048 chars, and the software team 1, does not wish to use SOAP, we implemented this via. Servlet. Is this the correct way of integrating the systems or should I try more on handling the hidden html param inside my REST API?

    • I’m not sure I understand what you’re trying to do based on your description, but hidden HTML sounds like a bad idea. If you have two different services, they should be independent and well defined. REST makes sense as well as choosing a serialization mechanism (e.g. JSON, XML). Whether you use a servlet or some other technology is neither here nor there.

  7. Thank you, Daniel!

    This is the perfect code!
    Regexp is the best decision I’ve ever seen!

    Best regards,
    Andrey

  8. Excellent post, this is same as the one which i was searching in internet . Looking for ways to implement REST without using any predefined frameworks.

  9. Thanks for this great tutorial. for example i want to handle many resource like /resource/id , /resourceabc/id and many more. what should i do? should i use reflection to map url pattern to a java class? or do you have better idea? Thanks

  10. Avatar for Daniel Watrous Jørgen Larsen : June 10, 2018 at 1:35 pm

    Had exactly the same problem – use of plain servlet for REST services. My solution contains some of the same items, but was not as elegant as this one. Thank you for this fantastic solution.

  11. can you help me understand if your implementation would handle path parameters?

  12. Thank you for this perfect tutorial!

    There is just one little thing:
    http://server/testrestservlet/api/vi/resource/id
    should be
    http://server/testrestservlet/api/v1/resource/id

Leave a Reply to Jørgen Larsen Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.