Reputation: 5880
I'm using Jersey-Guice to configure a Jersey app, following this template. Everything works fine if the Injector
returned by the GuiceServletContextListener.getInjector()
method is created by Guice.createInjector()
. If that injector is instead the child of another injector, then the bound resources (e.g., MyResource
in the code below) are never added to the Jersey ResourceConfig
and Jersey crashes with a complaint about missing root resources. I don't think the bound resources are even scanned, because the usual "INFO: Registering my.example.MyResource as a root resource class" doesn't appear in the log.
Any ideas why this might be happening? Both versions are show below.
As an additional question: I'm trying to use the child injector because I want to configure my application data service object in my Main() class. More than just the Jersey resources need access to it. I still need it injected into the Jersey resources.
If there's a better way to share the application singleton between the application Injector and servlet injector (better than my current approach of the servlet injector being a child of the application injector), please let me know.
This version works.
public class MyConfig extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
return Guice.createInjector(new ServletModule() {
@Override
protected void configureServlets() {
bind(MyResource.class);
serve("*").with(GuiceContainer.class);
}
});
}
}
The following code does not work though.
public class MyConfig extends GuiceServletContextListener {
final Injector parentInjector;
public MyConfig(Injector injector) {
this.parentInjector = injector;
}
@Override
protected Injector getInjector() {
return parentInjector.getChildInjector(new ServletModule() {
@Override
protected void configureServlets() {
bind(MyResource.class);
serve("*").with(GuiceContainer.class);
}
});
}
}
Upvotes: 3
Views: 1407
Reputation: 5880
I figured it out after some fun with the debugger.
The resources are discovered by iterating over the bindings of the injector, checking for those that are resources or providers. The injector used is injected into the GuiceContainer via a constructor like this: public GuiceContainer(@Inject injector)
. With no explicit binding for GuiceContainer.class specified in the child injector, the parent (i.e., root) injector is used to create the instance (just-in-time binding, I guess) and consequently the parent (not the child) injector is injected into to the GuiceContainer instance.
The fix is simple:
Explicitly bind GuiceContainer.class in the child injector. The following code works
public class MyConfig extends GuiceServletContextListener {
final Injector parentInjector;
public MyConfig(Injector injector) {
this.parentInjector = injector;
}
@Override
protected Injector getInjector() {
return parentInjector.getChildInjector(new ServletModule() {
@Override
protected void configureServlets() {
/* Explicitly bind GuiceContainer so that
* the child, not root, injector is injected
* into its constructor. */
bind(GuiceContainer.class);
bind(MyResource.class);
serve("*").with(GuiceContainer.class);
}
});
}
}
Upvotes: 5