Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining @Provides and @Inject

Tags:

guice

I've recently come across some code that uses both @Provides and @Inject annotations on the same method. This method has two non-primitive parameters and a non-void return type.

I was wondering whether it made sense to use these two in tandem. From what I can gather/speculate, it seems like @Inject is being used to construct the method dependencies using Guice, whereas @Provides is being used to bind the return type. Any ideas would be appreciated.

like image 625
OrangeApple3 Avatar asked Jun 17 '17 07:06

OrangeApple3


People also ask

What does @inject do in Guice?

Note that the only Guice-specific code in the above is the @Inject annotation. This annotation marks an injection point. Guice will attempt to reconcile the dependencies implied by the annotated constructor, method, or field.

What is @inject annotation in Guice?

@Target(value={METHOD,CONSTRUCTOR,FIELD}) @Retention(value=RUNTIME) @Documented public @interface Inject. Annotates members of your implementation class (constructors, methods and fields) into which the Injector should inject values. The Injector fulfills injection requests for: Every instance it constructs.

What does @inject annotation mean?

The @Inject annotation lets us define an injection point that is injected during bean instantiation.

How does @inject annotation work?

A method annotated with @Inject that overrides another method annotated with @Inject will only be injected once per injection request per instance. A method with no @Inject annotation that overrides a method annotated with @Inject will not be injected. Injection of members annotated with @Inject is required.


1 Answers

No, there is never a case where you'd see @Provides and @Inject on the same method.

@Inject makes sense on constructors, methods, and fields:

  • On constructors, it marks the constructor that the DI framework should call. The framework provides all parameter values. This is often called constructor injection.
  • On fields, it indicates that the DI framework should set the field from outside. The framework provides the field value. This is often called field injection.
  • On methods, it indicates that after construction the DI framework should call the method exactly once. The framework provides the parameter values. The return value is meaningless and often void. This is often called method injection.

For example:

public class YourInjectableClass {

  // Guice will use this constructor...
  @Inject public YourInjectableClass(YourDep dep) { /* ... */ }
  // ...instead of this one
  public YourInjectableClass(YourDep dep, YourOtherDep otherDep) { /* ... */ }

  // Guice will populate this field after construction.
  @Inject YourField yourField;

  @Inject public void register(Registry registry) {
    // Guice will create or get a Registry and call this method after
    // construction. It sometimes makes sense for this to be protected
    // or package-private so this class's consumers aren't tempted
    // to call it themselves.
  }
}

@Provides has a much narrower purpose: When used in Guice modules, @Provides goes on methods and indicates that Guice should call the method whenever it needs an instance of the method's possibly-parameterized type (and inheriting the binding annotations or qualifiers from the method itself). Dagger has a similar @Provides annotation, as @Provides isn't defined in the JSR-330 dependency injection standard.

For both Guice and Dagger, the framework will supply the @Provides method's parameters whenever the method is called, and without using @Inject. The semantics of @Inject wouldn't make sense anyway, since even though the parameters are supplied in a similar way to method injection above, the framework may call the @Provides method repeatedly but @Inject methods are called exactly once.

public class YourModule extends AbstractModule {
  @Override public void configure() {)  // still needed for AbstractModule

  // Guice will call this whenever it needs a
  // @SomeBindingAnnotation YourInstance. Because you list a YourDep as a
  // parameter, Guice will get and pass in a YourDep.
  @Provides @SomeBindingAnnotation YourInstance create(YourDep dep) {
    return YourInstanceFactory.create(dep);
  }
}

Consequently, you should almost never see those annotations in the same file, let alone on the same method. The only exception is if you follow the questionable practice of making a Module that is itself injectable (presumably getting an injected Module from one injector in order to configure a different injector), and even then you wouldn't see them on the same method: @Inject methods are called once to store dependencies, and @Provides methods should be called whenever a new instance is needed.

like image 177
Jeff Bowman Avatar answered Oct 01 '22 21:10

Jeff Bowman