3 Comments

Hooking up Custom Jersey Servlets in Dropwizard

I’ve been using the Dropwizard Java framework for about a year. It’s a great web application stack for making RESTful service with Java.

I recently ran into a situation where I wanted to add custom servlets to a Dropwizard application. Specifically, I wanted to add a Jersey servlet to the admin port of the application, to support some low level testing and admin functions. I also needed this servlet to support some of the built in Dropwizard things, like automatic serialization with Jackson and hibernate support.

Figuring out how to wire all of this up required a fun romp through some scattered internet forums and a lot of Dropwizard source code. In the hopes that it might help others, I though I would share what I learned here.

First off, here is all of the code needed to accomplish our goal.

DropwizardResourceConfig jerseyConfig = new DropwizardResourceConfig(environment.metrics());
JerseyContainerHolder servletContainerHolder = new JerseyContainerHolder(new ServletContainer(jerseyConfig));
 
environment.admin().addServlet(name, servletContainer.getContainer()).addMapping("/custom/*");
 
final FilterHolder holder = new FilterHolder(new GzipFilterFactory().build());
environment.getAdminContext().addFilter(holder, mountPoint, EnumSet.allOf(DispatcherType.class));
 
jerseyConfig.getSingletons().add(new JacksonMessageBodyProvider(Jackson.newObjectMapper(), environment.getValidator()));
jerseyConfig.getSingletons().add(new UnitOfWorkResourceMethodDispatchAdapter(hibernateBundle.getSessionFactory()));
jerseyConfig.getSingletons().add(new AdminResource(new AdminDAO()));

Now, let’s go through the code and break down each piece.

1. Create new jersey servlet

The first thing to do is actually create the servlet container, which is exposed by Jersey. It only needs a configuration which is conveniently provided by Dropwizard.

DropwizardResourceConfig jerseyConfig = new DropwizardResourceConfig(environment.metrics());
JerseyContainerHolder servletContainerHolder = new JerseyContainerHolder(new ServletContainer(jerseyConfig));

The configuration provided by Dropwizard enables lots of useful features, out of the box, like logging of resource endpoints and exception mappers.

2. Add the servlet to the dropwizard environment and map it

environment.admin().addServlet(name, servletContainer.getContainer()).addMapping("/custom/*);

3. Enable gzip

We need to add gzip filter so that incoming gzipped requests can be decoded.

final FilterHolder holder = new FilterHolder(new GzipFilterFactory().build());
environment.getAdminContext().addFilter(holder, mountPoint, EnumSet.allOf(DispatcherType.class));

4. Enable Jackson

Next, configure our new servlet is to add Jackson support for serializing and deserializing data. Again, through the magic of Dropwizard’s clean abstractions, this can be accomplished with a one liner.

jerseyConfig.getSingletons().add(new JacksonMessageBodyProvider(Jackson.newObjectMapper(), environment.getValidator()));

5. Add unit of work dispatchers for hibernate (if you are using hibernate)

I make heavy use of Dropwizard’s hibernate integration, which wraps all of the database connection setup and transaction work into the convenient UnitOfWork annotation. In order to make this annotation work, we have to add a special resource method dispatcher with our hibernate session factory.

jerseyConfig.getSingletons().add(new UnitOfWorkResourceMethodDispatchAdapter(hibernateBundle.getSessionFactory()));

6. Register resources

Now we can register our Jersey resource classes, just like for our main jersey servlet on our application.

jerseyConfig.getSingletons().add(new AdminResource(new AdminDAO()));

With that, we now have a fully running jersey servlet on the admin port of our application that we can use to do complex maintenance or testing operations. When you start up Dropwizard, you should even see the route listing for your custom servlet in the console output.