A Simple Java Web Stack With Guice, Jetty, Jersey and Jackson

Another Java web framework? Not really…

There are dozens of web technologies for Java (Struts, Stripes, Tapestry, Wicket, GWT, Spring MVC, Vaadin, Play, plain old servlets and JSP, Dropwizard, etc.) and they all have their advantages and disadvantages.

This article isn’t about comparing frameworks. Instead, I’ll describe how to serve HTTP requests from Java without using a monolithic framework in a way that’s a lot more pleasant than using just HttpServletRequests: Jetty for handling low-level HTTP things, Jersey for request routing, Jackson for serialization and Guice to tie it all together.

Update: If you actually want to write something quickly using stuff shown in this article, Dropwizard has since come out, and looks like a solid choice. If you want to learn more about how to build such a stack, check out the second article in this series.

If you want to write your web UI on the server side (whether it’s translated to JavaScript ala GWT or simply HTML markup like you might put in a JSP), this probably isn’t an approach that will be very attractive. You won’t have a web framework already there to provide pre-canned view helpers or login forms or “is this a phone number” validation or any of that. If you are transitioning towards making the server be more of a data store and putting display logic entirely in the client (regardless of whether the client is a browser or a native mobile app), the no-big-framework approach can make a lot of sense. You don’t need portlets or JavaScript components when you’re simply shoving JSON or XML or what-have-you over HTTP. I’ll be including code samples as new concepts are introduced, but if you want to browse the finished example project, it’s on the Team Lazer Beez GitHub site.

Jetty

Jetty is a HTTP server and servlet container that’s been designed expressly for easy embedding. I think it’s easier to do the edit-restart-test cycle with a simple main method that starts a Jetty server (no IDE I’ve used has ever had integration with a servlet container that works as fast or as reliably as running a main method). If you prefer to run and debug inside a separate container, or if you need container-managed security or JTA or XA or any of that stuff, feel free bundle your code as a war instead of using Jetty. Here’s how you start a Jetty server listening on localhost:8080.

Server server = new Server(8080);
// handlers go here
server.start();

Pretty easy! But, this server doesn’t do anything since we haven’t told it what to do for incoming requests. So, before we call start(), we need to give the server a Handler. Handlers are a Jetty concept that can do pretty much anything in response to a HTTP request. You might have a Handler that only gathers performance metrics or only does logging. In this case, we want a Handler that can invoke servlets.

ServletContextHandler handler = new ServletContextHandler();
handler.setContextPath("/");
// set up handler
server.setHandler(handler);

One odd thing about Jetty’s ServletContextHandler is that it likes to have one servlet always, even though in our case we won’t actually end up needing any to run our business logic. So, we’ll give the handler a servlet (InvalidRequestServlet) that always 404s.

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
    resp.setContentType("text/plain");
    resp.setContentType("UTF-8");
    resp.getWriter().append("404");
}

If you create a main method with the code to start up Jetty and run it, you should now be able to go to http://localhost:8080 in your browser and see the result of your InvalidRequestServlet. Before we can start adding some actual logic, though, I’ll need to explain Guice and its servlet layer.

Guice

Guice is a dependency injection framework. Though it accomplishes more or less the same job that Spring does, it has a slightly different philosophy. Whereas Spring tends to think in terms of bean ids when gluing code together, Guice tends to think in terms of types. They’re both good tools with different strengths, but I am only going to show how to use Guice (or this article will never end!). I’ll give a whirlwind tutorial in Guice and Guice Servlet and then we’ll get back to building our stack.

Making some PB&J Sandwiches

One of the problems (but not the only one) that DI/IoC frameworks like Guice and Spring are trying to solve is the problem of passing an instance through many layers of constructors just because some deep-down class is structured to take an instance of some interface. No doubt you’ve seen this anti-pattern: Class1 instantiates Class2 which instantiates Class3, but Class3 takes a Foo instance in its constructor, so somewhere higher up (perhaps in Class1, or even higher up than that) you create the correct Foo instance and then it gets passed around for a while until it’s finally used in Class3. This sucks, but it’s a worthy goal to have Class3 take a Foo instance in its constructor rather than directly instantiating some concrete implementation: this benefits testability, separation of concerns, etc.

Guice can help make this easier. As an example, let’s suppose that you have a SandwichMaker class that takes a PeanutButter implementation in its constructor. For testing your SandwichMaker, you may wish to use a mock PeanutButter implementation, but in an actual deployment you might wish to use an OrganicCrunchyValenciaPeanutButter (OCVPB for short).

class SandwichMaker {
// ...
    SandwichMaker(PeanutButter peanutButter) {
        this.peanutButter = peanutButter;
    }
// ...
}
interface PeanutButter {
    void applyToSandwich(Sandwich sandwich, int grams);
}

Now the question is where in your actual app do you instantiate your OCVPB? It’s not ideal to do it in the class that creates a SandwichMaker since that class will now be using actual peanut butter when it’s run during tests as it’s hardcoded the concrete implementation. It’s also not ideal to create the OCVPB in the top-level main method and pass the instance around through however many levels of constructors are needed to get to the SandwichMaker. To explain how we can use Guice to solve this problem, there are a few concepts to explain.

Guice concepts

Rather than explicitly creating instances with the new keyword, Guice lets you define how classes depend on each other and takes care of wiring things together for you. In our case, we want our SandwichMaker to have a PeanutButter implementation provided to it. We inform Guice of this by annotating the ctor with @Inject. (There are versions of Inject and some other classes from both com.google.inject and from the standardized JSR 330 javax.inject packages. They work almost exactly the same; check the Guice documentation for details. Just pick one and stick with it.)

class SandwichMaker {
// ...
    @Inject
    SandwichMaker(PeanutButter peanutButter) {
        this.peanutButter = peanutButter;
    }
// ...
}

Now that we’ve said that SandwichMaker needs a PeanutButter, we need to say which PeanutButter to use. We do this with a binding in a module. Modules are intended to represent functional boundaries in your application. The decision of when to put things in separate modules is like learning when to put things in separate packages: you’ll simply need to get a feel for it by trying it out. For now, let’s create a module that sets up everything you need to make sandwiches.

class SandwichModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(PeanutButter.class).to(OrganicCrunchyValenciaPeanutButter.class);
    }
}

This informs Guice to create a new instance of OCVPB whenever it sees a request to inject a PeanutButter instance. PeanutButter seems like the sort of thing that should be a singleton since it represents a real-life resource, though, so let’s go ahead and fix that:

bind(PeanutButter.class).to(OrganicCrunchyValenciaPeanutButter.class).in(Scopes.SINGLETON);

We could also have annotated our OCVPB implementation class with @Singleton to achieve the same effect. Now, no matter how many SandwichMakers we get, only one PeanutButter will be used. We create an Injector with all of the modules necessary (in this case, just the one module) and use it to get an instance of SandwichMaker. It will inspect the bindings and injection targets and create a OCVPB and pass it to the SandwichMaker ctor. We don’t actually need to get a standalone SandwichMaker instance, but if we did, this is how we would do it.

Injector injector = Guice.createInjector(new SandwichModule());

SandwichMaker maker = injector.createInstance(SandwichMaker.class);
// use the maker

This is just the very most basic usage of Guice. Check out their documentation for more details.

Guice Servlet

Now that we know how to bind instances (whether as singletons or new-one-every-time) and inject them, we can move on to Guice Servlet. This extension to Guice allows us to get rid of web.xml entirely (if embedding Jetty) or make it much simpler (if using a war). Suppose you have a FooServlet servlet. In the old days of web.xml, there would be servlet tags and servlet-mapping tags to wire it up. Here’s how it is with Guice Servlet:

class FooServletModule extends ServletModule {
    @Override
    protected void configureServlets() {
        bind(FooServlet.class);
        serve("/foo").with(FooServlet.class);

        // other servlets
    }
}

Since Guice is instantiating your FooServlet class intead of relying on the servlet container to invoke the 0-args ctor, this also means that you can use @Inject on the ctor and get the objects you need that way instead of pulling them out of init params or servlet context. To feed incoming requests into the servlets you’ve laid out with Guice Servlet, you need to set up GuiceFilter as a filter for all requests. You can do this in web.xml if you’re using a war (it’s the only thing you’ll actually need in web.xml) or just configure Jetty directly.

Injector injector = Guice.createInjector(new SandwichModule(), new AbstractModule() {
    @Override
    protected void configure() {
        binder().requireExplicitBindings();
        bind(GuiceFilter.class);
    }
});

FilterHolder guiceFilter = new FilterHolder(injector.getInstance(GuiceFilter.class));
handler.addFilter(guiceFilter, "/*", EnumSet.allOf(DispatcherType.class));

Now, you can stop here and bind your servlets in a ServletModule and get the benefits of being able to initialize your servlets with Guice, but it gets even easier with Jersey.

Jersey and Jackson

Jersey is the reference implementation of JAX-RS. It lets you do things like POST the url “http://localhost:8080/foo?bar=baz&quux=1234″ and handle the request with this class:

@Path("/foo")
@Produces(MediaType.APPLICATION_JSON)
class FooResource {
    @POST
    public String handleFooPost(@QueryParam("bar") String bar, @QueryParam("quux") int quux) {
       return "{\"yay\":\"hooray\"}";
    }
}

The class, method and parameter names are not magic; only the annotations are what ties this code to handling that request. Jersey will set the status code, content length, etc. appropriately. It can also do void methods (returns status 204 for you), streaming responses, and entirely custom responses (pick the status code, the entity, etc), so check the documentation for the details. If you use Jersey to handle actually calling your business logic instead of writing plain old servlets directly, you only need to have one servlet binding in your Guice Servlet module:

public class SandwichServletModule extends ServletModule {
    @Override
    protected void configureServlets() {
        // bind resource classes here

        // hook Jersey into Guice Servlet
        bind(GuiceContainer.class);

        // hook Jackson into Jersey as the POJO <-> JSON mapper
        bind(JacksonJsonProvider.class).in(Scopes.SINGLETON);

        serve("/*").with(GuiceContainer.class);
    }
}

GuiceContainer is a class that ships with Jackson. When you use GuiceContainer, all you need to do is bind the resource classes (like FooResource above) with Guice. The JacksonJsonProvider binding to make it easier to return objects as JSON; you’ll see what it does a bit later. To go back to our sandwich example, let’s suppose we have two resources: one to make sandwiches and one to say how many sandwiches have been made. Let’s start with the stats one (at /sandwich/stats) since it is simpler (doesn’t need to modify state). Supposing I have a SandwichStats class that can provide StatSnapshot objects that represent the total amount of jam, peanut butter and sandwiches, the resource is very simple:

@Singleton
@Produces(MediaType.APPLICATION_JSON)
@Path("/sandwich/stats")
public class SandwichStatsResource {

    private final SandwichStats sandwichStats;

    @Inject
    SandwichStatsResource(SandwichStats sandwichStats) {
        this.sandwichStats = sandwichStats;
    }

    @GET
    public SandwichStats.StatsSnapshot getStats() {
        return sandwichStats.getStats();
    }
}

You’ll also need to bind the resource class so that GuiceContainer can find it. When you have a lot of resources, you might want to put their bindings in a module just for that purpose, but for now just add a binding in SandwichServletModule:

bind(SandwichStats.class);

The resource requests a SandwichStats object in its ctor so that it can ask it for the latest info every time a request is made. The SandwichStats object should also be a singleton since we want it to live as long as the app is up. (Guice is easy to use for non-singletons too — it just happens that in this contrived example I seem to be ending up with lots of singletons.) Note that the @GET method returns an object, not a string. This is where the ImmutableMap.of(JSONConfiguration.FEATURE_POJO_MAPPING, "true") comes in. It tells Jersey to attempt to map the POJO returned from the method to JSON. To do this, we use the Jackson JSON library. Jackson is a fast JSON serialization/deserialization library, and one of its features is easy annotation-based configuration for POJO mapping. It’s probably easiest to just show what it looks like in practice:

public class StatsSnapshot {
    // ...
    @JsonProperty
    public int getSandwichesMade() {
        return sandwichesMade;
    }

    @JsonProperty
    public int getGramsOfJam() {
        return gramsOfJam;
    }

    @JsonProperty
    public int getGramsOfPeanutButter() {
        return gramsOfPeanutButter;
    }
}

When serialized by Jackson, an object of that class will end up as a JSON object with three keys (“gramsOfJam”, “gramsOfPeanutButter” and “sandwichesMade”). Since Jersey has been configured to automatically use Jackson to serialize objects, you can go to /sandwich/stats in your browser and get something like this: {"gramsOfJam":150,"gramsOfPeanutButter":200,"sandwichesMade":1} Now let’s add a resource that lets you make sandwiches. Normally I wouldn’t have something that modifies state be a GET but I want this to be easy to test in a browser, so let’s say that a GET to http://localhost:8080/sandwich/create will make a sandwich (with optional jam and peanutButter query parameters to specify how many grams of jam and peanut butter to use) and that the sandwich created should be returned as JSON. This is what such a resource might look like:

@Singleton
@Produces(MediaType.APPLICATION_JSON)
@ThreadSafe
@Path("/sandwich/create")
public class SandwichMakerResource {

    private final SandwichMaker sandwichMaker;

    private final SandwichStats sandwichStats;

    @Inject
    SandwichMakerResource(SandwichMaker sandwichMaker, SandwichStats sandwichStats) {
        this.sandwichMaker = sandwichMaker;
        this.sandwichStats = sandwichStats;
    }

    @GET
    public Sandwich makeSandwich(@QueryParam("jam") @DefaultValue("100") int gramsOfJam,
                                 @QueryParam("peanutButter") @DefaultValue("200") int gramsOfPeanutButter) {
        Sandwich sandwich = sandwichMaker.makeSandwich(gramsOfPeanutButter, gramsOfJam);
        sandwichStats.recordSandwich(sandwich);

        return sandwich;
    }
}

The resource (yet another singleton) gets SandwichMaker and SandwichStats instances injected, and whenever it makes a sandwich it updates the SandwichStats object. Try accessing it via your browser a few times and check the stats page to see that the counts do update correctly. I’ve only scratched the surface of what these libraries can do with this simple example. Let me know if you think there’s some cool feature I missed (as long as it won’t complicate things too much to work it in).

Posted by Marshall Pierce

Marshall specializes in highly tuned and immensely scalable web and mobile applications. Experienced in front-end web and iOS development, he constantly pushes the boundaries of the latest browsers and mobile platforms. He splits his time with back-end development, where he is considered a domain expert in Java concurrency, distributed systems, systems design, and network security. Prior to co-founding Palomino Labs, Marshall was director of software development at Ness Computing where he led their initial launch. Before Ness, Marshall was a senior software developer at Genius.com, where he built the best-in-class integration with Salesforce.com.

About Palomino Labs

Palomino Labs unlocks the potential of software to change people and industries. Our team of experienced software developers, designers, and product strategists can help turn any idea into reality.

See the Palomino Labs website for more information, or send us an email and let's start talking about how we can work together.