javadependency-injectionguiceroboguice

Guice @Provides Methods vs Provider Classes


I'm working on a fairly large project that has a lot of injections. We're currently using a class that implements Provider for each injection that needs one, and they mostly have one line get methods.

It's starting to get annoying to create a new class every time I need a new provider. Is there any benefit to using provider classes over @Provides methods in my Module or vice-a-versa?


Solution

  • As far as I know, they're exactly equivalent for most simple cases.

    /**
     * Class-style provider.
     * In module: bind(Foo.class).annotatedWith(Quux.class).toProvider(MyProvider.class);
     */
    class MyProvider implements Provider<Foo> {
      @Inject Dep dep;  // All sorts of injection work, including constructor injection.
    
      @Override public Foo get() {
        return dep.provisionFoo("bar", "baz");
      }
    }
    
    /**
     * Method-style provider. configure() can be empty, but doesn't have to be.
     */
    class MyModule extends AbstractModule {
      /** Name doesn't matter. Dep is injected automatically. */
      @Provides @Quux public Foo createFoo(Dep dep) {
        return dep.provisionFoo("bar", "baz");
      }
    
      @Override public void configure() { /* nothing needed in here */ }
    }
    

    In either style, Guice lets you inject Foo and Provider<Foo>, even if the key is bound to a class or instance. Guice automatically calls get if getting an instance directly and creates an implicit Provider<Foo> if one doesn't exist. Binding annotations work in both styles.

    The main advantage of @Provides is compactness, especially in comparison to anonymous inner Provider implementations. Note, however, that there might be a few cases where you'd want to favor Provider classes:


    IMPORTANT: Though this is a good strategy for classes that Guice can't create, bear in mind that Guice can automatically create and inject a Provider<T> for any T that you bind in any way, including to a class name, key, or instance. No need to create an explicit provider unless there's actual logic of your own involved.