Guice Request Scope: Do I need a Provider binding for a value seeded in a servlet filter?
guice, servlet-filters
Solution
You don't need any values from the request to create the executor service, so you don't need a filter. Just create a provider method in one of your modules
@Provides @RequestScoped
ExecutorService provideExecutor() {
return Executors.newFixedThreadPool(
10, ThreadManager.currentRequestThreadFactory());
}
Problem
I'm having some problems following the Guice wiki documentation for using RequestScope (https://code.google.com/p/google-guice/wiki/ServletModule#Using_RequestScope). I am trying to set up an application where I have a request-scoped ExecutorService. My use case is patterned off the example in the documentation - I've tried to include other relevant classes for completeness. The main difference is that I am instantiating an instance of ExecutorService within the Filter rather than pulling a literal value out of the request parameters: ``` @Singleton public class ExecutorServiceScopingFilter implements Filter { public ExecutorService getExecutor() { return Executors.newFixedThreadPool(10, ThreadManager.currentRequestThreadFactory()); @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { ExecutorService executor = getExecutor(); HttpServletRequest httpRequest = (HttpServletRequest) req; httpRequest.setAttribute(Key.get(ExecutorService.class).toString(), executor); chain.doFilter(req, resp); } ... } ``` In my servlet module I bind the filter: ``` public class MyServletModule extends ServletModule { @Override protected void configureServlets() { filter("/*").through(ExecutorServiceScopingFilter.class); ... } } ``` And I install the module as normal in my servlet context listener (I've set up the web.xml to use the guice filter and the below listener): ``` public class MyServletContextListener extends GuiceServletContextListener { @Override protected Injector getInjector() { Injector injector = Guice.createInjector( Stage.PRODUCTION, new MyServletModule(), new MyExampleModule(), ... ); } } ``` I declare the provider in an un-scoped POJO: ``` class MyExampleImpl implements IMyExample { @Inject protected Provider<ExecutorService> executorProvider; ... } ``` Which I bind in a module (and is a parameter of the createInjector call in my listener above): ``` public class MyExampleModule extends AbstractModule { @Override protected void configure() { bind(IMyExample.class).to(MyExampleImpl.class); } } ``` When I start my web app, I get the following exception: com.google.inject.CreationException: Guice creation errors: 1) No implementation for java.util.concurrent.ExecutorService was bound. while locating com.google.inject.Provider for field at com.example.MyExampleImpl.executorProvider(MyExampleImpl.java:12) at com.example.ExampleModule.configure(ExampleModule.java:23) 1 error I have found a related question that indicates the use of a bogus binding (Guice: Cannot inject annotated type in Request scope). The example given is: ``` bind(String.class) .annotatedWith(Names.named("name")) .toProvider(Providers.<String>of(null)); ``` I tried this for binding the ExecutorService and get a null for the provider (so the injector is returning the declared binding instead of using the binding defined by the filter). The use of a bogus binding is never mentioned in the official documentation. So a few questions to try and solve this problem and understand a bit more about how Guice operates: Do I need an explicit binding other than setting the attribute (in contrast to the Guice documentation)? If so, do I need to bind anything using the @RequestScope annotation? Do I need to make a provider that implements Provider? Inspecting an @Inject Injector object, I do not see the request-scoped binding for ExecutorService in the binding maps. Should I see this binding? Inspecting the requestScopeContext thread local variable in the ServletScope class at runtime, I do see the ExecutorService binding. This indicates that the binding is working, so I am not doing something (or doing something incorrectly) to access it.