1
How to Make Performance Testing More Efficient
2
Flexible Data Model Design
3
How to grow your project without failing at architecture, scalability and system integration
4
Fast creation of performance tests based on SoapUI project
5
How to Improve Performance of AWS Java Cloud App? Try ElastiCache
6
How You Can Use Cassandra in the Big Data World
7
Harnessing the chaos in software project management
8
Working in a Virtual Team
9
Database: How To Make a Bad Thing Work Well
10
Smart Version Control for Project Managers and Decision Makers

Request-scoped resources with Guice and Servlet

Our team was looking for a very simple Java Web framework for one of our projects, and we found the next combination of tools very fascinating:

  • Eclipse Jetty Web server for HTTP request interception
  • Google Guice for dependency injection
  • Java Servlet for request handling

They work together pretty well, and there is a plenty of articles on the Internet covering this topic, so it is easy to get things started. But none of these articles explains how to scope your code in a single HTTP request. By design, servlet is always a singleton. Guice refuses to register servlets as request-scoped objects, so, the whole point of request-scoped object instantiation is being lost. Due to this issue, we’ve almost decided to abandon an idea of using low-level servlets and switch to Jersey framework, which wasn’t very attractive for us as well, for different reasons. But a deeper look to Guice API has saved my day.

Just to clear things out, we’ve defined a dream class of HTTP resource that we wanted to work with and that we wanted to inherit other resources from.

package com.myapp.servlet.resource;

import com.google.inject.Inject;
import com.google.inject.servlet.RequestParameters;
import com.google.inject.servlet.RequestScoped;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

@RequestScoped
public abstract class Resource {

    @Inject protected HttpServletRequest request;
    @Inject protected HttpServletResponse response;
    @Inject @RequestParameters protected Map<String, String[]> params;

    public abstract void process() throws ServletException, IOException;
}

Granularity is the key. One Resource instance is created and called to process a single request regardless of HTTP method. The resource is request scoped.

Sample resource class.

package com.cassantec.frontend.servlet.resource;

import com.cassantec.frontend.servlet.exception.InvalidRequestException;
import com.cassantec.frontend.servlet.exception.WebException;

public class InvalidRequestResource extends Resource {

    @Override
    public void process() {
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        response.getWriter().print("Invalid request!");
    }
}

We’re going to use this InvalidRequestResource as a default resource for all requests which don’t match any routes.

Now we need to somehow make this work. Here’s a universal class of servlet that allows you to register such request-scoped resources in your Guice module with ease.

package com.myapp.servlet;

import com.myapp.servlet.resource.InvalidRequestResource;
import com.myapp.servlet.resource.Resource;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Singleton;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Singleton
public class ScopedServlet extends HttpServlet {

    private Class<? extends Resource> getResource;
    private Class<? extends Resource> postResource;
    @Inject private Injector injector = null;

    public ScopedServlet(Class<? extends Resource> getResource,
            Class<? extends Resource> postResource) {
        this.getResource = (getResource != null)
                ? getResource : InvalidRequestResource.class;
        this.postResource = (postResource != null)
                ? postResource : InvalidRequestResource.class;
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        invoke(getResource);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        invoke(postResource);
    }

    private void invoke(Class<? extends Resource> resourceClass)
            throws ServletException, IOException {
        injector.getInstance(resourceClass).process();
    }
}

In this snippet Guice magic happens: it turns out that Guice Injector registers itself as an injectable singleton object! To be honest, I was very surprised (in a good way) when I realized that it works this way. And even more wonderful: you don’t need to have an appropriate binding in the injector to instantiate objects of arbitrary class. Guice is quite smart, man! As a result, we were able to use the injector to instantiate request-scoped resources and process them inside the servlet.

So, ScopedServlet’s constructor takes two arguments: a resource class to process GET requests, and a resource class to process POST requests. To make this work, we must use instance bindings.

package com.myapp.servlet;

import com.myapp.account.AccountResource;
import com.myapp.company.CompanyResource;
import com.google.inject.servlet.ServletModule;

public class FrontendServletModule extends ServletModule {

    @Override
    protected void configureServlets() {
        serve("/account").with(
                new ScopedServlet(AccountResource.class, null));
        serve("/company").with(
                new ScopedServlet(CompanyResource.class, null));
        serve("/*").with(new ScopedServlet(null, null));
    }
}

Here one more Guice magic happens: it turns out that dependency injection is applied to instance bindings as well! You are not obligated to construct all objects via injector.getInstance method to make injections happen. In fact, a special injector.injectMembers method is exposed for you to deal with this problem. Guice is quite well-thought, man!

I hope that this article covers request-scoped resources definition problem good enough. To complete this example, see Full Example Code Showing How to Use Guice and Jetty or other related articles.

Maybe you still have some thoughts or questions left? If so, feel free to share in the comment box.

About the author

Egor Nepomnyaschih

Egor is an experienced software developer working with JavaScript, PHP, Java, Unity technilogies. He is happy to share his expertise with all the industry peers.

  • Yaroslav Borovikov

    Hi,

    Thanks for the post! It’s always interesting to see how different solutions can be implemented on top of amazing frameworks.

    But reality is that I totally missed the use case. What’s the purpose of having confined processing per each request?

    • enepomnyaschih

      The reason to use request-scoped resources is thread safety. You can safely define an instance field or inject a request-scoped service into your resource, and you don’t have to bother about how to prevent memory conflicts between two simultaneous servlet calls.

      For example, I prefer to introduce an AuthenticatedResource class which takes care of all authentication burden and exposes a protected “account” field. Since every servlet call instantiates a new AuthenticatedResource, I can be sure that “account” field is never modified occasionally by other threads.

  • andrey alekseenko

    I see only one reason for using this approach, you can’t write stateless servlets.

    • enepomnyaschih

      That’s right, servlet must be singleton by specification, and for multi-threaded application it means that servlet must be stateless. For me, it is inconvenient – I’d like to have stateful HTTP resources to work with.

      • andrey alekseenko

        I think you didn’t understand me.

        I mean you are not able to write thread-safe servlet. Probably, you know in theory but you can’t use knowledge in practice.

  • Александр Гончаров

    Nice post! However, I’m curious how is Jersey not attractive for you? It also has integration with guice