I have a doubt regarding which is the right place to set the injects attribute (not annotation) in dagger, when there are plus'ed graphs.
We have this scenario:
#Module(injects = ClassWithInjects.class, complete = false)
public final class BaseModule {
#Provides
DependencyA providesA() { return new A(); }
#Provides
DependencyB providesB() { return new B(); }
...
}
class ClassWithInjects {
#Inject
A a;
#Inject
B b;
}
that was working fine when doing:
ObjectGraph graph = ObjectGraph.create(new BaseModule()).plus(new Object[0]); // no modules used to plus by default
graph.inject(new ClassWithInjects());
Afterwards we added a new module that is the only one supposed to provide B from that moment on:
#Module(injects = ClassWithInjects.class, complete = false)
public final class BaseModule {
#Provides
DependencyA providesA() { return new A(); }
...
}
#Module(addsTo = BaseModule.class, complete = false)
public final class AdditionalModule {
#Provides
DependencyB providesB() { return new B(); }
}
class ClassWithInjects {
#Inject
A a;
#Inject
B b;
}
That is failing with
IllegalStateException No binding for B required by class
ClassWithInjects
when doing this:
ObjectGraph graph = ObjectGraph.create(new BaseModule()).plus(new AdditionalModule());
graph.inject(new ClassWithInjects());
It works when I move the
injects = ClassWithInjects.class
attribute from BaseModule to AdditionalModule.
So, where am I supposed to place the injects attribute when using plus'ed modules? Does it have to be in one of the modules used as parameters in the call to .plus(...)?
According to this github issue I have to put the injects in the module that has the bindings for the instance I try to inject dependencies into (ClassWithInjects in the example above) but, what if I have several modules providing the different bindings needed to fulfill all the dependencies of that instance? Do I have to create a module that includes all the others and put there the injects attribute?
Have you seen the Android sample here: https://github.com/square/dagger/tree/master/examples/android-activity-graphs/src/main/java/com/example/dagger/activitygraphs
Comparing that setup to what you have, the "injects" were defined on the Module that was plussed. I think a current limitation is that you have to define those on every plussed Module in the case where you have multiple.
Related
I want to write Espresso tests for an app so I'm trying DaggerMock to
mock some external dependencies like local storage.
My Dagger setup consists of an ApplicationComponent with 3 modules (DatabaseModule, DataModule and ApplicationModule) and for the screen( a Fragment ) I want to test I have also another component which depends on ApplicationComponent.
What I have tried so far is :
#Rule public DaggerMockRule<ApplicationComponent> daggerRule =
new DaggerMockRule<>(ApplicationComponent.class, new DatabaseModule(), new DataModule(application),
new ApplicationModule(application)).set(
component -> {
MyApplication app =
(MyApplication) InstrumentationRegistry.getInstrumentation()
.getTargetContext()
.getApplicationContext();
app.setComponent(component);
});
#Rule
public final DaggerMockRule<FeedComponent> rule = new DaggerMockRule<>(
FeedComponent.class, new FeedDataSourceModule(),
new FeedDownloadImageUseCaseModule(), new FeedServiceModule(), new FeedPresenterModule(null))
.addComponentDependency(ApplicationComponent.class, new DatabaseModule(), new DataModule(application), new ApplicationModule(application))
.set(component -> localDataSource = component.localDataSource());
#Mock FeedDao feedDao;
#Mock NetworkUtils networkUtils;
#Mock FeedLocalDataSource localDataSource;
where localDataSource is actually the dependency I want to mock and it's build in FeedDataSourceModule :
#Module
public class FeedDataSourceModule {
#Provides
#FragmentScope
public FeedItemMapper providesFeedItemMapper() {
return new FeedItemMapper();
}
#Provides
#FragmentScope
public FeedLocalDataSource providesFeedLocalDataSource(FeedDao feedDao, FeedRequestDetailsDao detailsDao, FeedItemMapper mapper) {
return new FeedLocalDataSourceImpl(feedDao, detailsDao, mapper);
}
#Provides
#FragmentScope
public FeedRemoteDataSource providesFeedRemoteDataSource(FeedService feedService, FlagStateService flagStateService,
#Named("Api-Token") String apiToken, #Named("Screen-Size") String screenSize,
#Named("Account-Id") String accountId) {
return new FeedRemoteDataSourceImpl(feedService, flagStateService, apiToken, screenSize, accountId);
}
}
and also the FeedComponent with the dependency on ApplicationComponent :
#FragmentScope
#Component( dependencies = ApplicationComponent.class,
modules = {
FeedPresenterModule.class,
FeedServiceModule.class,
FeedDataSourceModule.class,
FeedDownloadImageUseCaseModule.class})
public interface FeedComponent {
#Named("Api-Token") String getApiToken();
#Named("Api-Key") String getApiKey();
FeedLocalDataSource localDataSource();
FeedRemoteDataSource remoteDataSource();
void inject(FeedFragment feedFragment);
}
With the two #Rules I posted above I can confirm that NetworkUtils indeed seems to have been mocked correctly since I have used Mockito.when() to return false value and by using a breakpoint in my code I can see the value is always false :
when(networkUtils.isOnline())
.thenReturn(false);
But this is not true for localDataSource which gives me null when I'm calling localDataSource.getFeedSorted() although I have declared :
when(localDataSource.getFeedSorted())
.thenReturn(Flowable.just(feedList));
Just in case it helps, this is how I inject the dependencies from FeedComponent :
DaggerFeedComponent.builder()
.applicationComponent(MyApplication.getApplicationComponent())
.feedPresenterModule(new FeedPresenterModule(this))
.build()
.inject(this);
Why are you using two DaggerMock rules in a test? I think you can use a single rule like in this example.
I am not sure what the difference is? When should I use which?
http://square.github.io/dagger/javadoc/index.html
includes indicates which modules current module is composed of. For example, it's useful for aggregating all your modules statically:
#Module(
includes = { AndroidModule.class, NetworkModule.class, StorageModule.class }
)
public class RootModule() {
}
// other file
objectGraph = ObjectGraph.create(new RootModule());
Instead of dynamically:
objectGraph = ObjectGraph.create(
new AndroidModule(),
new NetworkModule(),
new StorageModule());
Thus, fully utilizing compile time graph validation.
addsTo relates specifically to parent-child modules' relations. It indicates that module is an extension of some module and is used as .plus() parameter. E.g. having two modules:
#Module(
//...
)
public class ParentModule() {
//...
}
#Module(
addsTo = { ParentModule.class },
//...
)
public class ChildModule () {
//...
}
this config means that after parentGraph = ObjectGraph.create(new ParentModule()); you can execute childGraph = parentGraph.plus(new ChildModule()); somewhere in your code to create extended, usually, short-lived child graph.
I have read many blogs but still i am not able to figure out #Module annotation functioning in dagger.
#Inject i got that it provides dependency injection at runtime. But what does #Module does.
since the object graph is also built on module.
For ex i.e i have this snippet of code from https://github.com/AndroidBootstrap/android-bootstrap.
#Module(
complete = false,
injects = {
BootstrapApplication.class,
BootstrapAuthenticatorActivity.class,
MainActivity.class,
BootstrapTimerActivity.class,
}
)
public class BootstrapModule {
}
so what does it basically does. since i am also trying to build one application using dagger as dependency injection for android.But since I am not able to get #Module concept clearly I am just stuck.
Can anyone please help me out with some basic example or concept. I think this will be helpful for all who is using dagger.
If you have a look to the docs for the annotation, a #Module annotated class defines a class that contributes to the dagger object graph. In the Spring framework for example, the equivalent would be the #Configuration anntotation. It defines a configuration point for your object graph, where you declare which objects you want to be available for injection and their scopes.
As a simple example, let's say we want a singleton object to be used by any Activity in the app. It has to be created in the module:
#dagger.Module(injects = {MyActivity.class})
public class Module {
#Provides
#Singleton
public MySinletonBean provideMySingleton() {
return new MySinletonBean();
}
}
This will create a MySingleton object which can be injected in MyActivity. This is a very basic example, but we can perform other actions in the graph there, like using dependencies in the constructors:
#dagger.Module(injects = {MyActivity.class})
public class Module {
private DependencyBean dependency = new DependencyBean();
#Provides
#Singleton
public MySinletonBean provideMySingleton() {
return new MySinletonBean(dependency);
}
#Provides
#Singleton
public MySinletonBean provideMyOtherSingleton() {
return new MyOtherSinletonBean(dependency);
}
}
Then, in MyActivity we need to access the graph for the application in the onCreate method:
#Inject
MySingletonBean singleton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
((MyApplication) getApplication()).getGraph().inject(this);
}
So, who does create the object graph here? The MyApplication class does it when your application starts (don't forger to add it in your androidManifest.xml):
public class MyApplication extends Application {
private ObjectGraph graph;
public ObjectGraph getGraph() {
return graph;
}
#Override
public void onCreate() {
super.onCreate();
graph = ObjectGraph.create(new Module(this));
graph.inject(this);
}
}
So the execution flow in a dagger app would be:
The android app starts and the MyApplication class builds the graph, parsing the #Module annotated classes and keeping an instance of it.
Then, the classes declared in the module can access its objects just injecting themselves in the object graph. Gradle then will evaluate their #Inject annotations and perform the dependency injections.
I guess Annotation Processing Tool requires that to generate code at the compile time.
This makes it Dagger can provide validation at compile time and not only at runtime.
I have an Android app that uses Dagger. There are certain sections of the entire app that I want to add scoped ObjectGraphs for several activities that share a common scope. The following module is in the root ObjectGraph
#Module(
injects = {
MyApplication.class,
},
complete = false,
library = true)
public class BasicContextManagerModule {
private Context applicationContext;
public BasicContextManagerModule(Context applicationContext) {
this.applicationContext = applicationContext;
}
#Provides
Context getApplicationContext() {
return applicationContext;
}
}
Then I try to add the following Module through existingObjectGraph.plus(new FileManagerModule());
#Module(
injects = {
MyListActivity.class,
MyFileDetailActivity.class,
MyFileInfoActivity.class,
},
includes = BasicContextManagerModule.class
)
public class FileManagerModule {
#Provides
FileManager provideFileManager(Context context) {
return new FileManager(context);
}
}
But the result is
java.lang.UnsupportedOperationException: No no-args constructor com.myapp.core.modules.BasicContextManagerModule$$ModuleAdapter
Can someone help me understand why the plus won't allow this? I read from the dagger documentation that plus extends the object graph and you can have includes and addsTo Modules. But I haven't been able to achieve this.
includes means the module will live in the same subgraph, and Dagger will instantiate it if you don't pass an instance.
addsTo means the referenced module is expected to be in the graph (actually in a parent graph) but Dagger won't provide it for you.
What you want is addsTo.
Guice user, trying to understand a bit of the benefits of Dagger here.
Let's say I have the following
MyActivity.java
---------------
public class MyActivity {
#Inject MyImplicitClass myImplicitClass;
#Inject #Named("foo") MyExplicitClass myNamedExplicitClass;
...
}
MyImplicitClass.java
------------
public class MyImplicitClass {
#Inject
MyImplicitClass(MyExplicitClass myExplicitClass) {
...
}
...
}
MyModule.java
---------------
#Module(injects = { ? }) {
#Provides provideExplicitClass() {
return new MyExplicitClass();
}
#Named("foo") #Provides provideNamedExplicitClass() {
return new MyExplicitClass();
}
}
So, my question is, what should go in the Injects?
I know for a fact that MyActivity needs to go. Or rather, whatever "this" needs to have DaggerInjector.inject(this)
Does anything else?
Would Dagger the implicit construction injection class (MyImplicitClass) and/or the class explicitly provided in the module (MyExplicitClass) to also be specified?
MyExplicitClass wouldn't even make sense if I need it to be annotated.
However, the javadoc makes me feel I should error the side of inclusion
http://square.github.io/dagger/javadoc/dagger/Module.html#injects()
Dagger 1 does it's validation at compile therefore it needs all of the entry point you're going to use at runtime (objectgraph.get(entrypoint), objectgraph.inject(entrypoint)).
Entry points are the injectable classes which are at the top of the dependency graph. In Android most of the time those are your Activities, Fragments, Services, Broadcast Receivers. All compontents which are not created by Dagger. You would also list classes which are not part of any entry point's dependency tree again becoming an entry point of their own.
Those entry point are use to do validation by Dagger. Dagger will start validation at the entry points and tricle down the dependency tree and validate dependencies annotated with #Inject and #Provides from your Modules.
So in conclusion only entry points needs to be provided in the #Module(injects = { * })
In your example because the MyImplicitClass is an #Inject dependency of your entry point MyActivity you don't need to specify it in the #Modules(injects={}). The same is true for your MyExplicitClass dependency. Therefore from your example the only class that needs to be added to the list is in fact MyActivity.
Base on your example code, if you had something like this.
// MyIndependantClass.java
-----------------
public class MyIndependantClass {
#Inject
MyIndependantClass(MyExplicitClass myExplicitClass) {
}
}
// MyActivity.java
---------------
public class MyActivity {
#Inject MyImplicitClass myImplicitClass;
#Inject #Named("foo") MyExplicitClass myNamedExplicitClass;
...
protected void onCreate (Bundle savedInstanceState) {
MyIndependantClass myIndependantClass = MyObjectGraph.get(MyIndependantClass.class);
...
}
}
The fact that MyIndependantClass is created using ObjectGraph.get() and is not a direct dependency of your MyActivity entry point you would need to declare that class part of the injects list.
// MyModule.java
---------------
#Module(injects = { MyActivity.class, MyIndependantClass.class }) {
#Provides provideExplicitClass() {
return new MyExplicitClass();
}
#Named("foo") #Provides provideNamedExplicitClass() {
return new MyExplicitClass();
}
}