Latest Tweet

After using Google Guice for a while, I have come to love it.  I feel the same way about MongoDB, especially with all the new features they’ve been adding since 1.0.  Following the shiny object, like I do sometimes, I wanted a good way to combine the two.  In my own projects I have done this a few different ways, but kept finding the need for something just slightly different.  Eventually I ended up with a few features I would want in this kind of library:

  • annotation-based selection of the database or collection to inject
  • easy to understand configuration (via Guice or other configuration sources)
  • ability to map a database key to the actual database name (e.g. always refer to the “User” database, but map it to “prod_user” or “test_user” in the configuration)
  • ability to have configurations that map database/collection keys to different names for different environments, like Test, QA, and Production

To explain the approach I have gone with, I won’t waste any more time and just show some code examples.

Injector injector = Guice.createInjector(
  GuiceyMongo.configure("TEST")
    .mapDatabase("MAIN").to("test")
    .mapCollection("USER").to("user").inDatabase("MAIN"),

  GuiceyMongo.configure("PROD")
    .mapDatabase("MAIN").to("prod")
    .mapCollection("USER").to("user").inDatabase("MAIN"),

  GuiceyMongo.chooseConfiguration("TEST")
);

Here I create two configurations, TEST and PROD and set up a MAIN database and a USER collection in each.  I can map any number of databases and collections within a configuration.  Above, the TEST configuration for database key MAIN is mapped to actual database “test” and the PROD configuration for the same key is mapped to actual database “prod”.  As for collection mappings, both map the USER collection key to actual collection “user” within their respective databases.  Collection mappings must reference a mapped database key.

The last line is very important and should only exist once in your application.  It activates one of the configurations that you have set up.  Only the mappings within the chosen configuration will be active. This could be passed in from a command line argument and then set in the injector creation for more flexibility.

Now that we have defined our configurations and created an injector, how do we request an injection of a specific database or collection?  Using annotations of course!  The @GuiceyMongoDatabase annotation is used with a database key to inject a DB object, and the @GuiceyMongoCollection annotation is used with a collection key to inject a DBCollection object.

public class Foo {
  @Inject
  Foo(@GuiceyMongoDatabase("MAIN") DB database,
    @GuiceyMongoCollection("USER") DBCollection collection) {
    ...
  }
}

When working on a large application, it’s probably a good idea to create classes that encapsulate the required databases or collections for the individual module and then create your mappings from a central location that installs all the modules.

public class UserModule extends AbstractModule {
  public static final class Collections {
    private Collections() {}
    public static final String User = "USER";
  }

  @Override
  protected void configure() {
    ...
  }
}
public class ApplicationModule extends AbstractModule {
  public static final class Configurations {
    private Configurations() {}
    public static final String Production = "PROD";
    public static final String Test = "TEST";
  }
  public static final class Databases {
    private Databases() {}
    public static final String Main = "MAIN";
  }

  private final String _configuration;
  public ApplicationModule(String configuration) {
    _configuration = configuration;
  }

  @Override
  protected void configure() {
    install(new UserModule());
    install(GuiceyMongo.configure(Configurations.Test)
      .mapDatabase(Databases.Main).to("test")
      .mapCollection(UserModule.Collections.User).to("user").inDatabase(Databases.Main)
    ),
    install(GuiceyMongo.chooseConfiguration(_configuration));
  }
}

Hopefully this quick walkthrough piques your interest in GuiceyMongo and gives you an idea of how easy the setup actually is. There are more features implemented and I have more planned. I’ll be blogging about other features in the future, so check back periodically!

If you would like to use GuiceyMongo, it is available to the public:

I plan on maintaining and enhancing this library regularly and would love to hear your input! If you use my library, please leave me a comment so I know that people are finding it useful. Thanks!

blog comments powered by Disqus