Eureka!
I managed to integrate Guice into Dropwizard 0.6.0-SNAPSHOT using the third approach.
- It turns out that you cannot drop ServletFilter because it's responsible for maintaining @RequestScope and other important things.
- It also turns out that JerseyServletModule requires GuiceContainer.class to be injectable. This means you cannot simply pass a singleton into JerseyServletModule.filter().
Here is what I did:
- JerseyServletModule remains unchanged
- Replace GuiceContainer(Injector) with three constructors that mirror and delegate to the ServletContainer constructors
- The private Injector field changes from "private final Injector injector" to "@Inject private Injector injector". In other words, we use property injection instead of constructor injection. I believe this is a lesser evil to the current situation.
That's it! Here is the updated GuiceContainer:
@Singleton
public class GuiceContainer extends ServletContainer {
private static final long serialVersionUID = 1931878850157940335L;
@Inject
private Injector injector;
private WebApplication webapp;
public class ServletGuiceComponentProviderFactory extends GuiceComponentProviderFactory {
public ServletGuiceComponentProviderFactory(ResourceConfig config, Injector injector) {
super(config, injector);
}
@Override
public Map<Scope, ComponentScope> createScopeMap() {
Map<Scope, ComponentScope> m = super.createScopeMap();
m.put(ServletScopes.REQUEST, ComponentScope.PerRequest);
return m;
}
}
/**
* Creates a new container.
*/
public GuiceContainer() {
}
/**
* Creates a new container.
*
* @param app the JAX-RS application
*/
public GuiceContainer(Application app) {
super(app);
}
/**
* Creates a new container.
*
* @param app the JAX-RS application
*/
public GuiceContainer(Class<? extends Application> app) {
super(app);
}
@Override
protected ResourceConfig getDefaultResourceConfig(Map<String, Object> props,
WebConfig webConfig) throws ServletException {
return new DefaultResourceConfig();
}
@Override
protected void initiate(ResourceConfig config, WebApplication webapp) {
this.webapp = webapp;
webapp.initiate(config, new ServletGuiceComponentProviderFactory(config, injector));
}
public WebApplication getWebApplication() {
return webapp;
}
}
Here is a sample application:
public class Main extends Service<Configuration>
{
public static void main(String[] args) throws Exception
{
new Main().run(args);
}
@Override
public void initialize(Bootstrap<Configuration> bootstrap)
{
}
@Override
public void run(Configuration configuration, Environment environment) throws Exception
{
// Add resources using dropwizard. Horay!
environment.addResource(RootResource.class);
// Pass the resourceConfig into GuiceContainer
GuiceContainer container = new GuiceContainer(environment.getJerseyResourceConfig());
environment.setJerseyServletContainer(container);
environment.addServletListeners(new JerseyContextListener(container, new UserModule()));
environment.addFilter(GuiceFilter.class, configuration.getHttpConfiguration().getRootPath());
}
}
public class JerseyContextListener extends GuiceServletContextListener
{
private final Injector injector;
public JerseyContextListener(GuiceContainer container, Module... modules)
{
this.injector = Guice.createInjector(Lists.asList(new JerseyModule(container), modules));
}
@Override
protected Injector getInjector()
{
return injector;
}
}
public class JerseyModule extends JerseyServletModule
{
private final GuiceContainer container;
/**
* Creates a new JerseyModule.
* <p/>
* @param container a container binding Jersey to Guice
*/
public JerseyModule(GuiceContainer container)
{
this.container = container;
}
@Override
protected void configureServlets()
{
bind(GuiceContainer.class).toInstance(container);
filter("/*").through(GuiceContainer.class);
}
}