Reputation: 273
I'm trying to inject a ViewModelProvider.Factory and I'm having trouble understanding why I'm not able to use a @Binds annotation.
This annotation seems to work:
@Binds
abstract ViewModelProvider.Factory bindViewModelFactory(ViewModelFactory viewModelFactory);
Combined with the following annotation, the project compiles:
@Provides
@IntoMap
@ViewModelKey(MyViewModel.class)
static ViewModel MyViewModel(){
return new MyViewModel();
}
However, if the above code is replaced with the following:
@Binds
@IntoMap
@ViewModelKey(MyViewModel.class)
abstract ViewModel bindMyViewModel(MyViewModel viewModel);
All of a sudden I get the following error message:
...MyViewModel cannot be provided without an @Inject constructor or an @Provides-annotated method.
Can someone explain why the first case works and the second doesn't? As I've understood @Binds, it should create a class of the return type, of the concrete implementation that's passed as a parameter.
Upvotes: 2
Views: 435
Reputation: 95614
As egoldx discussed in the comments, you need to annotate your MyViewModel constructor with @Inject
if you want Dagger to call it. As you mentioned, this means that JSR-330 defines @Inject
to have multiple valid uses:
To be especially clear here, Dagger's behavior documented in the User's Guide:
Use
@Inject
to annotate the constructor that Dagger should use to create instances of a class. When a new instance is requested, Dagger will obtain the required parameters values and invoke this constructor.
...contradicts JSR-330's definition of @Inject
, in that public parameterless constructors are not eligible to be called:
@Inject
is optional for public, no-argument constructors when no other constructors are present. This enables injectors to invoke default constructors.
The discussion around this deviation is in Square's Dagger 1 repository, issue #412 and Google's Dagger 2 issue #1105. In summary, the extra clarity was deemed useful (particularly given the number of objects that you could accidentally inject with default constructors), the extra cost of adding @Inject
was determined not to be too burdensome, and it avoids some ambiguity about whether subclasses are eligible for injection without having to inspect the entire class hierarchy for @Inject
fields.
Upvotes: 1