Dropwizard Hibernate

The dropwizard-hibernate module provides you with managed access to Hibernate, a powerful, industry-standard object-relation mapper (ORM).

Configuration

To create a managed, instrumented SessionFactory instance, your configuration class needs a DataSourceFactory instance:

public class ExampleConfiguration extends Configuration {
    @Valid
    @NotNull
    private DataSourceFactory database = new DataSourceFactory();

    @JsonProperty("database")
    public DataSourceFactory getDataSourceFactory() {
        return database;
    }

    @JsonProperty("database")
    public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
        this.database = dataSourceFactory;
    }
}

Then, add a HibernateBundle instance to your application class, specifying your entity classes and how to get a DataSourceFactory from your configuration subclass:

private final HibernateBundle<ExampleConfiguration> hibernate = new HibernateBundle<ExampleConfiguration>(Person.class) {
    @Override
    public DataSourceFactory getDataSourceFactory(ExampleConfiguration configuration) {
        return configuration.getDataSourceFactory();
    }
};

@Override
public void initialize(Bootstrap<ExampleConfiguration> bootstrap) {
    bootstrap.addBundle(hibernate);
}

@Override
public void run(ExampleConfiguration config, Environment environment) {
    final PersonDAO dao = new PersonDAO(hibernate.getSessionFactory());
    environment.jersey().register(new UserResource(dao));
}

This will create a new managed connection pool to the database, a health check for connectivity to the database, and a new SessionFactory instance for you to use in your DAO classes.

Your application’s configuration file will then look like this:

database:
  # the name of your JDBC driver
  driverClass: org.postgresql.Driver

  # the username
  user: pg-user

  # the password
  password: iAMs00perSecrEET

  # the JDBC URL
  url: jdbc:postgresql://db.example.com/db-prod

  # any properties specific to your JDBC driver:
  properties:
    charSet: UTF-8
    hibernate.dialect: org.hibernate.dialect.PostgreSQLDialect

  # the maximum amount of time to wait on an empty pool before throwing an exception
  maxWaitForConnection: 1s

  # the SQL query to run when validating a connection's liveness
  validationQuery: "/* MyApplication Health Check */ SELECT 1"

  # the minimum number of connections to keep open
  minSize: 8

  # the maximum number of connections to keep open
  maxSize: 32

  # whether or not idle connections should be validated
  checkConnectionWhileIdle: false

Usage

Data Access Objects

Dropwizard comes with AbstractDAO, a minimal template for entity-specific DAO classes. It contains type-safe wrappers for SessionFactory’s common operations:

public class PersonDAO extends AbstractDAO<Person> {
    public PersonDAO(SessionFactory factory) {
        super(factory);
    }

    public Person findById(Long id) {
        return get(id);
    }

    public long create(Person person) {
        return persist(person).getId();
    }

    public List<Person> findAll() {
        return list(namedTypedQuery("com.example.helloworld.core.Person.findAll"));
    }
}

Transactional Resource Methods

Dropwizard uses a declarative method of scoping transactional boundaries. Not all resource methods actually require database access, so the @UnitOfWork annotation is provided:

@GET
@Path("/{id}")
@Timed
@UnitOfWork
public Person findPerson(@PathParam("id") LongParam id) {
    return dao.findById(id.get());
}

This will automatically open a session, begin a transaction, call findById, commit the transaction, and finally close the session. If an exception is thrown, the transaction is rolled back.

If you are using more than one Hibernate bundle in your application, you can repeat the @UnitOfWork annotation:

@GET
@Path("...")
@Timed
@UnitOfWork(value = "hibernate.<db-name-1>")
@UnitOfWork(value = "hibernate.<db-name-2>")
public ...

In this case, the above specified behaviour applies to all given databases.

If multiple @UnitOfWork annotations with the same value() are provided, the last one is used.

Important

The Hibernate session is closed before your resource method’s return value (e.g., the Person from the database), which means your resource method (or DAO) is responsible for initializing all lazily-loaded collections, etc., before returning. Otherwise, you’ll get a LazyInitializationException thrown in your template (or null values produced by Jackson).

Transactional Resource Methods Outside Jersey Resources

Currently creating transactions with the @UnitOfWork annotation works out-of-box only for resources managed by Jersey. If you want to use it outside Jersey resources, e.g. in authenticators, you should instantiate your class with UnitOfWorkAwareProxyFactory.

SessionDao dao = new SessionDao(hibernateBundle.getSessionFactory());
ExampleAuthenticator exampleAuthenticator = new UnitOfWorkAwareProxyFactory(hibernateBundle)
               .create(ExampleAuthenticator.class, SessionDao.class, dao);

It will create a proxy of your class, which will open a Hibernate session with a transaction around methods with the @UnitOfWork annotation.

Prepended Comments

Dropwizard automatically configures Hibernate to prepend a comment describing the context of all queries:

/* load com.example.helloworld.core.Person */
select
    person0_.id as id0_0_,
    person0_.fullName as fullName0_0_,
    person0_.jobTitle as jobTitle0_0_
from people person0_
where person0_.id=?

This will allow you to quickly determine the origin of any slow or misbehaving queries.