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.
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:
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.