Dagger2: wildcard with Generics - dagger-2

I'm new to Dagger2 and DI in general, but I'm interested to populate a map with injected keys/values. The problem is that it works if I provide the exact types, I can't make it work with wildcards, any solution for that?
#Module
public class SimpleIssueModule
{
#Provides
#Singleton
#IntoMap
#StringKey("simple_issue")
public SimpleIssue provideSimpleIssue()
{
return new SimpleIssue();
}
}
#Module
public class DaggerFactoryModule
{
#Provides
#Singleton
public Factory provideFactory(Map<String, Provider< ? extends Issue>> map)
{
return new Factory(map);
}
}

If you want a map of Provider< ? extends Issue>> map, then you need to use Issue as the type returned in your module. Dagger will not do any casting or guessing on its own.
#Provides
#Singleton
#IntoMap
#StringKey("simple_issue")
public Issue provideSimpleIssue() {
return new SimpleIssue();
}
what to do in case I need a Module that provides a base class (Issue) into a Map and also need a provider of the concrete class (SimpleIssue) and I would like it to be Singleton (same instance returns in both cases)
In this case you provide the #Singleton of SimpleIssue.
#Provides
#Singleton
public SimpleIssue provideSimpleIssue() {
return new SimpleIssue();
}
// or you can use constructor injection, dropping the method above...
#Singleton
public class SimpleIssue {
#Inject
public SimpleIssue(...) {
}
}
Then you bind this instance into a Map. There is no need for a scope, since the implementation should declare it (as done above).
#Provides
#IntoMap
#StringKey("simple_issue")
public Issue provideSimpleIssue(SimpleIssue issue) {
return issue;
}
// or alternatively with `#Binds` when using an abstract class / interface
// this leads to actually better performing dagger code
#Binds
#IntoMap
#StringKey("simple_issue")
public Issue provideSimpleIssue(SimpleIssue issue);

Related

Infinite recursion when using subcomponent for encapsulation

I'm trying to achieve encapsulation by using subcomponent which is described here, but I got infinite recursion.
Here is my code:
//tried adding #ScopeA, still the same.
public class A {
#Inject
A(B b) {
}
}
#ScopeA
public class B {
#Inject
B() {
}
}
#Component(modules = AModule.class)
#Singleton
public interface AComponent {
public A a();
}
#Module(subcomponents = SComponent.class)
class AModule {
#Provides
#Singleton
A a(SComponent.Factory factory) {
return factory.component().a();
}
}
#Subcomponent
#ScopeA
interface SComponent {
#ScopeA
A a();
#Subcomponent.Factory
interface Factory {
SComponent component();
}
}
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAComponent.create().a();
}
}
After checking generated dagger code, I found this:
private final class SComponentImpl implements SComponent {
private SComponentImpl() {}
#Override
public A a() {
return DaggerAComponent.this.aProvider.get();
}
}
It seeems that SComponent are getting A from parent component, which is not what I wanted, where is the problem of my code?
Note that the example from the Subcomponents for Encapsulation page uses a qualifier annotation, #PrivateToDatabase, which is not a scoping annotation and which distinguishes the binding of Database from the binding of #PrivateToDatabase Database.
Subcomponents inherit all of the bindings from their parent components, so you currently do have A available from the parent component and also A available from the subcomponent. This is especially tricky if anything in your subcomponent needs to inject A, if it weren't marked #Singleton: Do you want the A from the parent component, or the A from the subcomponent?
Another tricky part of this situation is that you can't use qualifier annotations on classes that use #Inject constructors.
I'd recommend that you do the following:
Extract an interface from A, so then you have A and AImpl.
Keep your #Provides method that gets an A instance from the subcomponent.
Have the subcomponent expose AImpl, and (to best avoid ambiguity) only inject AImpl in the classes in your subcomponent, not A.
If you'd rather not extract an interface, you could also work around this problem by removing #Inject from A and writing a #Provides method in a module in the subcomponent that returns a qualified A, so the unqualified A goes through the top-level component and the qualified A is only available within the subcomponent.

Constructor injecting make MissingBinding in dagger 2 and mvp

I have created simple project with dagger2 and mvp.
This is my component :
#MainScope
#Component(modules = {MainModule.class})
public interface IMainComponent {
void inject(MainActivity mainActivity);
}
and This is MainModule.class:
#Module
public class MainModule {
#MainScope
#Provides
IMain.IMainModel model() {
return new MainModel();
}
}
Now in presenter i want to inject presenter from it's constructor so i do :
public class MainPresenter implements IMain.IMainPresenter {
IMain.IMainModel model;
IMain.IMainView view;
#Inject
public MainPresenter(IMain.IMainModel model) {
this.model = model;
}
But i got This error:
symbol: class DaggerIMainComponent
location: package com.safarayaneh.engineer.main.di
E:\Projects\Android\NewEng\Engineer\engineer\src\main\java\com\safarayaneh\engineer\main\di\IMainComponent.java:9: error: [Dagger/MissingBinding] com.safarayaneh.engineer.main.mvp.IMain.IMainPresenter cannot be provided without an #Provides-annotated method.
When make provider in MainModule.class to create presenter and remove #Inject above presenter constructor , everything is fine:
#Module
public class MainModule {
#MainScope
#Provides
IMain.IMainModel model() {
return new MainModel();
}
#MainScope
#Provides
IMain.IMainPresenter presenter(IMain.IMainModel model) {
return new MainPresenter(model);
}
}
Your problem is that your Activity expects IMain.IMainPresenter, but if you just annotate the constructor then what's placed on the objects graph is the concrete MainPresenter.
You've got three options here:
Use explicit provider method (as you did)
Use #Binds annotation inside the module to specify that MainPresenter should be provided as IMain.IMainPresenter
Don't use interface for the presenter

Does Dagger2 Initialize Objects it does not use?

I have a #Module class that has many #Provides methods. My #Component takes a dependency on this Module class. Ex:
#Singleton
#Component(modules = { MyModule.class})
public interface MyComponent {
ObjectA getObjectA();
ObjectB getObjectB();
}
#Module
public class MyModule {
#Provides
#Singleton
ObjectC provideObjectC() {
return new ObjectC();
}
#Provides
#Singleton
ObjectD provideObjectD() {
return new ObjectD();
}
#Provides
#Singleton
ObjectA provideObjectA(ObjectC objectC) {
return new ObjectA(objectC);
}
#Provides
#Singleton
ObjectB provideObjectB(ObjectD objectD) {
return new ObjectB(objectD);
}
}
I create an instance of the component using the Dagger builder, and provide a new instance of MyModule. If I only call myComponent.getObjectA() will it also construct ObjectB (and its dependencies), or are those left unconstructed?
Ran a manual test of the code I provided in the question with logging. If your injection only uses ObjetA, it will create ObjectA and ObjectC, but it will not create ObjectB or ObjectD.
It's been a while since I've used Dagger but you should specify those as parameters in the provide statement for it to work correctly. It will manage calling your other provider methods to grab the singleton instances.
#Provides
#Singleton
ObjectB provideObjectB(ObjectD objectD) {
return new ObjectB(objectD);
}
Or else you can also specify it as an injected constructor. See Dagger 2 injecting parameters of constructor

About Dagger 2. Connection of #inject and #provide

If there is #inject, then it means there must be #provide?
inject field gets its value from #provide method of module?
Yes if you use Module
#Module
public class SomeModule {
#Provides
Unscoped unscoped() {
return new Unscoped();
}
#Provides
#Singleton
Scoped scoped() {
return Scoped();
}
}
BUT classes with #Inject constructor get automatically appended to your scoped component even if no module is specified for it:
#Singleton
public class Scoped {
#Inject
public Scoped() {
}
}
public class Unscoped {
#Inject
public Unscoped() {
}
}
If there is #Inject annotation then it's dependency can be provided in two ways :
By Using Provides annotation in module
#Provides
TasksPresenter provide TasksPresenter(TasksRepository tasksRepository, TasksContract.View tasksView) {
return new TasksPresenter(tasksRepository,tasksView);
}
By Using Constructor Injection
#Inject
TasksPresenter(TasksRepository tasksRepository, TasksContract.View tasksView) {
mTasksRepository = tasksRepository;
mTasksView = tasksView;
}
One thing to observe here is Constructor Injection solve two thing
Instantiate object
Provides the object by adding it to Object graph.

Dagger2 - where define the scopes

I have a small question to Dagger2.
But first let me show the sample code:
#Singleton
#Component(module={ApplicationModule.class})
public Interface ApplicationComponent {
}
#Module
public class ApplicationModule {
#Provides
public Context provideContext() {
return context;
}
}
I know that the objects from the component now are "Singletons"..
My question... Did that have any effect to the Module? Is the Module also Singleton?
No, the Module will not be singleton unless you specify the scope for the #Provides annotated provider methods as well.
#Singleton
#Component(module={ApplicationModule.class})
public Interface ApplicationComponent {
Context context;
}
#Module
public class ApplicationModule {
#Provides //unscoped, every injection is new instance
public Context context() {
return context;
}
#Provides
#Singleton //scoped, one instance per component
public Something something() {
return new Something();
}
}