This is the last article of Dropwizard series, that outlines how to use Google Guice as a lightweight way to add dependency injection capabilities while developing RESTful web services using Dropwizard.

The source code for this article is here on GitHub

What is Guice?

Guice is a dependency injection framework that you can use to write application that follows IoC paradigm. You can say it's about writing more loosely coupled modules that rely on each other's contracts for interoperability, rather then choosing specific implementation. Next, it's about taking object creation boilerplate out of your classes and replacing it with dependency injection that is handled by Guice. That not only makes your code more clean, but a way more testable too.

Example is worth more than paragraphs of text, so here's basic example of code without dependency injection.

public class UserService {
    private final UserDao userDao;

    public UserService() {
        userDao = new UserDaoJdbcImpl();
        userDao.setDatabaseConnection(DriverManager.getConnection("jdbc:mysql://localhost/test"));
    }

    public void save(User user) {
        userDao.save(user);
    }
}

While basic, some problems start to emerge:

  • It gets even more complicated when UserDao needs to be further initialised or have some more properties set
  • Testing this is not really possible without exposing UserDao to package
  • Switching between different UserDao implementations, say UserDaoMongoImpl instead of UserDaoJdbcImpl would require changing code in this class

And when done with dependency injection:

public class UserService {
    private final UserDao userDao;

    @Inject
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public void save(User user) {
        userDao.save(user);
    }
}

So what happened to creation and initialization od UserDao, where it's now? The answer to this question, from UserService perspective is... I really don't care and don't want to care at all, ask Guice guy. All I care is talking to UserDao interface when needed.

Adding Guice Maven dependency

So you can just take your pom.xml and add:

<dependency>
    <groupId>com.google.inject</groupId>
    <artifactId>guice</artifactId>
    <version>3.0</version>
</dependency>

Integrating Guice with Dropwizard

So, let's take a look on the ExampleService class from previous tutorial. It should look like that:

public class ExampleService extends Service<ExampleServiceConfiguration> {

    public static void main(String[] args) throws Exception {
        new ExampleService().run(args);
    }

    @Override
    public void initialize(Bootstrap<ExampleServiceConfiguration> bootstrap) {
        bootstrap.setName("dropwizard-example");
    }

    @Override
    public void run(ExampleServiceConfiguration conf, Environment env) throws Exception {
        env.addResource(new HelloResource(conf.getMessages()));
    }

}

So, we have a nice run() method there, that we can use to create Guice Injector:

@Override
public void run(ExampleServiceConfiguration conf, Environment env) throws Exception {
    Injector injector = Guice.createInjector();
    env.addResource(injector.getInstance(HelloResource.class));
}

Thing to notice: instead of writing new HelloResource(conf.getMessages()) we asked Injector to create instance for us via its getInstance() method. This way, if created instance is dependant on anything else, it will get injected during instance creation. But, what happened to conf.getMessages() part? Of course, it should be injected, but that requires rewriting of HelloResource.

Using @Inject

@Path(value = "/hello")
public class HelloResource {

    private final MessagesConfiguration conf;

    @Inject
    public HelloResource(MessagesConfiguration conf) {
        this.conf = conf;
    }

    @GET
    public String sayHello() {
        return conf.getHello();
    }

}

This rewriting was really about adding @Inject annotation over the constructor. This annotation can also be added on object properties and method parameters as well, but I prefer it that way.

One can ask how does Guice know what exactly to inject here. Well, by default matching is by type, and every injection leads to creating a new instance of this type.

Example of binding type to specific instance of Dropwizard configuration class

But, this is configuration, right? There exists only one instance filled by Dropwizard with configuration parameters for us, that is passed to the run() method of ExampleService. So if it's new instance injected, or if we did conf = new MessagesConfiguration(), the properties of this object would be null!

That's why we need to tell Guice that if anything requests injection of MessagesConfiguration type, then it should be bound to existing instance initialized by Dropwizard.

@Override
public void run(ExampleServiceConfiguration conf, Environment env) throws Exception {
    Injector injector = createInjector(conf);
    env.addResource(injector.getInstance(HelloResource.class));
}

private Injector createInjector(final ExampleServiceConfiguration conf) {
    return Guice.createInjector(new AbstractModule() {
        @Override
        protected void configure() {
            bind(ExampleServiceConfiguration.class).toInstance(conf); // if someone would like to @Inject ExampleServiceConfiguration
            bind(MessagesConfiguration.class).toInstance(conf.getMessages()); // for ExampleResource, which does @Inject MessagesConfiguration
        }
    });
}

I have extracted createInjector() private method to keep Injector initialisation stuff separate. To customize behaviour of Injector the Guice.createInjector() method takes a parameter which is subclass of AbstractModule. This has one abstract method configure() where we can define some bindings. In this example we have bound types to specific and existing instance of our configuration classes. Hence, when ExampleResource will have MessagesConfiguration injected, it will get this one specific instance instead of new, empty object.

There are other ways to customize bindings, as well as instance scopes, but that's really Guice-specific and they are described in documentation.

JPA with Dropwizard using guice-persist

Dropwizard provides JDBI support out of the box for database access, but sometimes one might want to use JPA instead. For any application it would be excellent if the EntityManager could just be injected, without all configuration hassle. That's why there is a guice-persist - an extension to Guice that takes care of it for us.

First, some dependencies for Maven. I will use EclipseLink as JPA provider, and MySQL database connector. So, things to add to pom.xml:

<dependency>
    <groupId>com.google.inject.extensions</groupId>
    <artifactId>guice-persist</artifactId>
    <version>3.0</version>
</dependency>
<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>eclipselink</artifactId>
    <version>2.5.1</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.30</version>
</dependency>

You'll need persistence.xml on the classpath, so put it into src/main/resources/META-INF/persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
    <persistence-unit name="Default" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="eclipselink.ddl-generation" value="create-tables"/>
            <property name="eclipselink.ddl-generation.output-mode" value="database"/>
        </properties>
    </persistence-unit>
</persistence>

That will create persistence unit with name Default. Notice that I didn't put any database-specific information in it. That's because I don't want to keep this kind of stuff separate from Dropwizard configuration. I just want to have one configuration file for entire application.

Using Dropwizard configuration with guice-persist

Next, we need configure Guice with JpaPersistModule provided by guice-persist. So, let's get back to the place where Injector was created...

private Injector createInjector(final ExampleServiceConfiguration conf) {
    return Guice.createInjector(new AbstractModule() {
        @Override
        protected void configure() {
            bind(ExampleServiceConfiguration.class).toInstance(conf); // if someone would like to @Inject ExampleServiceConfiguration
            bind(MessagesConfiguration.class).toInstance(conf.getMessages()); // for ExampleResource, which does @Inject MessagesConfiguration
        }
    }, new JpaPersistModule("Default"));
}

I have added JpaPersistModule to Guice.createInjector() just after my unnamed AbstractModule. The constructor parameter is persistence unit name, which is Default. But still, I want to add configuration to it, so it knows how to reach my database, and I didn't do it in persistence.xml.

For that purpose I wrote DatabaseConfiguration class that will be contained within main configuration class, which is ExmpleServiceConfiguration in this case.

public class DatabaseConfiguration {

    @NotNull
    private String driverClass;
    private String user;
    private String password;
    @NotNull
    private String url;

    // getters and setters omitted for readability
}

Now I have to just put them into JpaPersistModule, which can be done like this:

private Injector createInjector(final ExampleServiceConfiguration conf) {
    return Guice.createInjector(new AbstractModule() {
        @Override
        protected void configure() {
            // custom bindings go here, omitted
        }
    }, createJpaPersistModule(conf.getDatabase()));
}

private JpaPersistModule createJpaPersistModule(DatabaseConfiguration conf) {
    Properties props = new Properties();
    props.put("javax.persistence.jdbc.url", conf.getUrl());
    props.put("javax.persistence.jdbc.user", conf.getUser());
    props.put("javax.persistence.jdbc.password", conf.getPassword());
    props.put("javax.persistence.jdbc.driver", conf.getDriverClass());
    JpaPersistModule jpaModule = new JpaPersistModule("Default");
    jpaModule.properties(props);
    return jpaModule;
}

This will use DatabaseConfiguration object to initialize JpaPersistModule, so all the information about database connection could be kept in Dropwizard's configuration file.

Using PersistFilter with Dropwizard

There is one issue to resolve before we can use EntityManager and it goes down to the question when the database connection should be ready. Since this is a RESTful web service that performs some actions when client accesses it, it's obvious that the right time for it is on request. That's why guice-persist provides PersistFilter that will listen to the request lifecycle and prepare a connection for us to use.

Connecting PersistFilter is easy and can be done in run() method of our service:

@Override
public void run(ExampleServiceConfiguration conf, Environment env) throws Exception {
    Injector injector = createInjector(conf);
    env.addFilter(injector.getInstance(PersistFilter.class), "/*");
    env.addResource(injector.getInstance(HelloResource.class));
}

Example of using guice-persist in DAO

Let's take UserDao that appeared in the first example, and create implementation that will use EntityManager for accessing database.

public interface UserDao {
    void save(User user);
}

public class UserDaoImpl implements UserDao {
    @PersistenceContext
    private EntityManager em

    @Override
    @Transactional
    public void save(User user) {
        em.persist(user);
    }
}

We are not injecting EntityManager directly, because instance of this class will probably be created just after application starts running, together with some Resource class that could have injected UserService that will be using this class to persist users. Whereas EntityManager will be ready to use after client request. ~~So, instead of injecting directly I'm injecting Provider that is used to provide EntityManager when the method is actually called.~~ Actually, I just annotate it with @PersistenceContext which does that ;)

Another thing that appears here is @Transactional annotation. It just automagically opens a transaction on database before method executes and commits it after it ends.

Summary

I have shown you some goodies that Guice can provide when used together with Dropwizard. It's a nice and lightweight alternative to write RESTful webservices having the power of dependency injection container, and without using heavier things like Spring or CDI. As you can see it can also be used to simplify database access with JPA and database transaction management.

This site uses cookies. By continuing to browse the site, you are agreeing to our use of cookies. Find out more in Privacy and Cookies Policy.