/dropwizard-guice

Adds support for Guice in Yammer's Dropwizard damn simple library for building production-ready RESTful web services.

Primary LanguageJavaApache License 2.0Apache-2.0

Dropwizard-Guice

A simple DropWizard extension for integrating Guice via a bundle. It optionally uses classpath scanning courtesy of the Reflections project to discover resources and more to install into the dropwizard environment upon service start.

Usage

    <dependencies>
        <dependency>
            <groupId>com.hubspot.dropwizard</groupId>
            <artifactId>dropwizard-guice</artifactId>
            <version>0.7.0.2</version>
        </dependency>
    </dependencies>

Simply install a new instance of the bundle during your service initialization

public class HelloWorldApplication extends Application<HelloWorldConfiguration> {

  private GuiceBundle<HelloWorldConfiguration> guiceBundle;

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

  @Override
  public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {

    guiceBundle = GuiceBundle.<HelloWorldConfiguration>newBuilder()
      .addModule(new HelloWorldModule())
      .setConfigClass(HelloWorldConfiguration.class)
      .build();

    bootstrap.addBundle(guiceBundle);
  }

  @Override
  public String getName() {
    return "hello-world";
  }

  @Override
  public void run(HelloWorldConfiguration helloWorldConfiguration, Environment environment) throws Exception {
    environment.jersey().register(HelloWorldResource.class);
    environment.lifecycle().manage(guiceBundle.getInjector().getInstance(TemplateHealthCheck.class));
  }
}

You can enable auto configuration via package scanning.

public class HelloWorldApplication extends Application<HelloWorldConfiguration> {

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

  @Override
  public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {

    GuiceBundle<HelloWorldConfiguration> guiceBundle = GuiceBundle.<HelloWorldConfiguration>newBuilder()
      .addModule(new HelloWorldModule())
      .enableAutoConfig(getClass().getPackage().getName())
      .setConfigClass(HelloWorldConfiguration.class)
      .build();

    bootstrap.addBundle(guiceBundle);
    // with AutoConfig enabled you don't need to add bundles or commands explicitly here.
    // inherit from one of InjectedCommand, InjectedConfiguredCommand, or InjectedEnvironmentCommand
    // to get access to all modules during injection.
  }

  @Override
  public String getName() {
    return "hello-world";
  }

  @Override
  public void run(HelloWorldConfiguration helloWorldConfiguration, Environment environment) throws Exception {
    // now you don't need to add resources, tasks, healthchecks or providers
    // you must have your health checks inherit from InjectableHealthCheck in order for them to be injected
  }
}

Configuration data will be auto-injected and named. Use the provided @Config annotation to specify the path to the configuration data to be injected.

public class HelloWorldConfiguration extends Configuration {
    @JsonProperty
    private String template;

    @JsonProperty
    private Person defaultPerson = new Person();

    public String getTemplate() { return template; }

    public Person getDefaultPerson() { return defaultPerson; }
}

public class Person {
    @JsonProperty
    private String name = "Stranger";
    private String city = "Unknown";

    public String getName() { return name; }
}

public class HelloWorldModule extends AbstractModule {

    // configuration data is available for injection and named based on the fields in the configuration objects
    @Inject
    @Config("template")
    private String template;

    // defaultPerson.name will only be available if the Person class is defined within the package path
    // set by addConfigPackages (see below)
    @Inject
    @Config("defaultPerson.name")
    private String defaultName;

    // A root config class may also be specified.  The path provided will be relative to this root object.
    @Inject
    @Config(Person.class, "city")
    private String defaultCity;

    @Override
    protected void configure() {
    }
}

Modules will also be injected before being added. Field injections only, constructor based injections will not be available. Configuration data and initialization module data will be available for injecting into modules.

public class HelloWorldApplication extends Application<HelloWorldConfiguration> {

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

  @Override
  public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {

    GuiceBundle<HelloWorldConfiguration> guiceBundle = GuiceBundle.<HelloWorldConfiguration>newBuilder()
      .addInitModule(new BaseModule())
      // bindings defined in the BaseModule or any configuration data is available for
      // injection into HelloWorldModule fields
      .addModule(new HelloWorldModule())
      //Any resource, task, bundle, etc within this class path will be included automatically.
      .enableAutoConfig(getClass().getPackage().getName())
      //The contents of any config objects within this package path will be auto-injected.
      .addConfigPackages(getClass().getPackage().getName())
      .setConfigClass(HelloWorldConfiguration.class)
      .build();

    bootstrap.addBundle(guiceBundle);
  }

  @Override
  public String getName() {
    return "hello-world";
  }

  @Override
  public void run(HelloWorldConfiguration helloWorldConfiguration, Environment environment) throws Exception {
  }
}

If you are having trouble accessing your Configuration or Environment inside a Guice Module, you could try using a provider.

public class HelloWorldModule extends AbstractModule {

  @Override
  protected void configure() {
    // anything you'd like to configure
  }

  @Provides
  public SomePool providesSomethingThatNeedsConfiguration(HelloWorldConfiguration configuration) {
    return new SomePool(configuration.getPoolName());
  }

  @Provides
  public SomeManager providesSomenthingThatNeedsEnvironment(Environment env) {
    return new SomeManager(env.getSomethingFromHere()));
  }
}

You can also replace the default Guice Injector by implementing your own InjectorFactory. For example if you want to use Governator you can create the following implementation:

public class GovernatorInjectorFactory implements InjectorFactory {

  @Override
  public Injector create( final Stage stage, final List<Module> modules ) {
    return LifecycleInjector.builder().inStage( stage ).withModules( modules ).build()
        .createInjector();
  }
}

and then set the InjectorFactory when initializing the GuiceBundle:

@Override
public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {

  GuiceBundle<HelloWorldConfiguration> guiceBundle = GuiceBundle.<HelloWorldConfiguration>newBuilder()
    .addModule(new HelloWorldModule())
    .enableAutoConfig(getClass().getPackage().getName())
    .setConfigClass(HelloWorldConfiguration.class)
    .setInjectorFactory( new GovernatorInjectorFactory() )
    .build();

 bootstrap.addBundle(guiceBundle);
}

Please fork an example project if you'd like to get going right away.

Enjoy!