Guice: How to use an instance instead of a Provider when I already have the instance

StackOverflow https://stackoverflow.com/questions/21738804

  •  10-10-2022
  •  | 
  •  

Question

I'm using Guice 4.0 Beta 2 on a new project after having used Guice 3.0 on a previous project.

In my current project there is an ApplicationConfiguration object this is derived from the HTTP request using an ApplicationConfigurationProvider:

  @Inject
  public ApplicationConfigurationProvider(HttpServletRequest request)
  {
    this.request = request;
  }

  @Override
  public ApplicationConfiguration get()
  {
    ApplicationConfiguration app = null;

    Map<String, ApplicationConfiguration> appMap = 
            (Map<String, ApplicationConfiguration>) request.getSession()
            .getServletContext()
            .getAttribute(ContextKeys.APPLICATION_CONFIGURATIONS.toString());

    //get the host.....
    String host = request.getServerName();
    if(host.equals("localhost"))
    {
      app = appMap.get("abcclient");
    }
    else
    {
      app = appMap.get("xyzclient");
    }

    return app;
  }

The binding looks like this:

bind(ApplicationConfiguration.class).toProvider(ApplicationConfigurationProvider.class).in(RequestScoped.class);

So far so good. This works as expected. Please note that other Provider classes depend on having the ApplicationConfiguration injected into them.

This is where I'm having trouble: I have some batch processing that needs to happen. The batch process is not initiated by an HTTP request. I have the correct ApplicationConfiguration instance available (it doesn't need to be selected by using the HTTP request) but I don't know how to bind this, or tell the Injector to use this instance rather than the ApplicationConfigurationProvider.

I thought I could create a custom scope and seed it with the ApplicationConfiguration instance that I wanted to use for that scope, but it didn't work. I created the custom scope using the example on the Guice wiki.

I thought I could bind the ApplicationConfiguration to some other type of Provider in the custom scope, but that didn't work either, because Guice only allows a particular key to be bound once.

In summary, I need to bind ApplicationConfiguration to a particular instance that I already have when in "batch" mode (when I have it available outside of a request), and use the ApplicationConfiguratoniProvider when inside an HTTP request. I'm hoping that if I have the ApplicationConfiguration instance, the other Providers into which it will be injected will work as they do now (when inside an HTTP request).

How can I do that?

Thank you!!!!

-Ryan

Was it helpful?

Solution 2

OK, I figured it out.

What I really wanted to do was reuse the RequestScope outside of an HTTP request, but I didn't think it was easily possible. It turns out it is, and the ServletScopes.scopeRequest method is what I needed.

This comment on the Guice forum is what actually led me on the right path:

https://groups.google.com/d/msg/google-guice/ozexD9etcXI/40kbz1PDdIEJ

I seeded the seedMap with the few request scoped variables that were defined in the injector bindings, created the Callable as shown, and it worked!

Here is the JavaDoc, which says that the scopeRequest method does just what I wanted it to do:

http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/servlet/ServletScopes.html

Thank you to everybody for the help!!

OTHER TIPS

There's numerous ways to approach this. If you know whether the application is in "batch" mode or normal mode at startup, you can do this:

@Override
public void configure() {
    if (isInBatchMode) {
        bind(ApplicationConfiguration.class)
                .toInstance(batchInstance);
    } else {
        bind(ApplicationConfiguration.class)
                .toProvider(ApplicationConfigurationProvider.class)
                .in(RequestScoped.class);
    }
}

Where isInBatchMode and batchInstance are passed in to the Module. Or you can make two different modules and install different ones depending on the configuration, etc.

You can also write a custom provider that returns the instance from the request if you're inside an HTTP request, and the "batch" instance otherwise. You can check if you're in an HTTP request with a custom filter.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top