I came across the dagger library from Square and I'm currently making some tests. I'm new to the DI principle so be kind :)
So, I understand Dagger can inject fields and constructors. I'm also aware that in my activities, I have to .inject(this); so that injection can be done at runtime.
But what about an object O that needs to be created after the activity initialization ?
If O has injectable fields, I have to .inject(O); before using it otherwise I get a NullPointerException when accessing its injected variables. But if I write a injectable constructor, no problem, no runtime exception.
Of course I wrote my #Module according to the documentation.
Isn't it the purpose of Dagger to injects fields with no other code to write ? Do I have to manually .inject(); all my objects ? There is for sure a thing I'm missing.
Thanks in advance.
As you wrote Dagger supports two kind of injection:
field injection
constructor injection
In the first case you create an object then you inject the fields using inject method. For example in your onCreate of an Activity you will call this:
mObjectGraph.inject(this);
The second type of injection (constructor injection) requires that the object is created by Dagger. You simply mark the constructor with #Inject annotation then you can create instance like this:
HasInjectableConstructor instance = mObjectGraph.get(HasInjectableConstructor.class);
That's it. Maybe Dagger 2 will change something in this matter: squ.re/dagger2
Related
I am new to Dagger, though I understand that injection can be achieved in two ways(as far as I can conclude) that by injecting constructor using #Inject and by using #Provide in the Module.
Still my conclusion doesn't have a valid point wrt to realtime scenarios and example.
Any suggestions will be helpful. Thank You
Yes, there are two types of injection, Constructor and Field injection.
Annotating fields for injection tells dagger to inject the proper object into them.
Annotating constructor for injection tells dagger to inject required objects and also allows dagger to create an instance of the class if it was needed somewhere else.
On the other hand, there is #Provide which is something different. with 'Provide' you provide dagger with required objects and dagger will inject them wherever they are needed. You define how to instantiate an object for injection.
So I am currently in the process of learning dagger 2, and from the tutorials that I've read so far, for a dependency to be injected, the #Inject annotation gets placed inline with fields (for Activities/Fragments) or constructors. However I see that as an issue if I'm not the owner of parts of the code and can't add the required annotations for this technique to work, or if I don't want other parts of the code to know that dagger exists.
The application structure I have at the moment is:
App Module - where I'd like to put my DI code in (e.g. dagger modules, etc).
Presentation Module - Views/ViewModels etc.
Domain Module - Use Cases etc.
Data Module - Repositories etc.
With pretty much this style of classes contained in my application:
class ExampleViewModelImpl(useCase: ExampleUseCase): ViewModel() in Presentation (gets initialised from an Activity or similar).
class ExampleUseCaseImpl(repository: ExampleRepository): ExampleUseCase in Domain
class ExampleRepositoryImpl(dao: ExampleDao): ExampleRepository in Data
With the structure above, what is the minimum number of classes outside of the App Module that I need to touch in order to utilize dagger with as much automated dependency injection as possible? Code examples of how this is achieved would be great.
I am unsure of some terminologies, and wasn't able to find a solution online. If there are good resources which explains what I'm asking, that would also be great.
if I don't want other parts of the code to know that dagger exists.
#Inject is a standard (JSR 330) which Dagger implements. Adding those annotations doesn't have anything to do with Dagger and can be used the same way with other DI frameworks. If it's your code you should just add those #Inject annotations where appropriate. Think of them as documentation: What constructor/field/method must be injected to create & use this object?
The only place where your classes will know that Dagger exists is at the same place where you'd be creating the objects otherwise, too.
Going down that path, of course you could use Dagger without any #Inject annotations, but you'd be writing a lot of unnecessary boilerplate and missing out on the most powerful feature of Dagger at the same time (code generation).
#Inject annotation gets placed inline with fields (for Activities/Fragments) or constructors. However I see that as an issue if I'm not the owner of parts of the code and can't add the required annotations for this technique to work
That's what #BindsInstance with the #Component.Builder is for (add an object to the component) and what #Provides annotated methods are for (create and initialize an object from a module)
If you really want to write code without #Inject, then you'd do exactly this for all of your objects. This means a lot of modules, and even more #Provides annotated methods. It will work, but I don't see the point in writing all those methods if a single #Inject on the constructor has the same effect.
In my opinion the best thing about Dagger is that I can add / remove / change constructor parameters and don't have to touch any other parts of my code since Dagger will generate new code with the new arguments. In your case you'd have to also change the parameters to the #Provides method as well as the constructor invocation.
Next let's look at how to remove #Inject from fields. Basically you don't want to do field injection, so instead of writing an injection method in the component, you'd write provision methods.
#Component
class MyComponent {
fun inject(activity: MyActivity)
}
class MyActivity {
#Inject lateinit var myDep: Dependency
fun onCreate() {
component.inject(this)
}
}
Removing the #Inject we need to use the provision methods instead.
#Component
class MyComponent {
fun provisionMyDependency() : Dependency
}
class MyActivity {
lateinit var myDep: Dependency
fun onCreate() {
myDep = component.provisionMyDependency()
}
}
It will work and everything, but again, you will miss out on the single best feature of Dagger: Code generation. The example above looks alright because I only added a single dependency, but think about what happens to those 2 different implementations when you add / remove / change dependencies, how well it will scale. If you prefer to do things manually any refactoring will become arduous.
With the structure above, what is the minimum number of classes outside of the App Module that I need to touch in order to utilize dagger with as much automated dependency injection as possible?
Your question (especially the title) is in direct conflict with your goal. If you don't want to use those annotations, then you can't use Dagger code generation & injection but have to resort to do it manually as highlighted above.
with as much automated dependency injection as possible
To best utilize Dagger you add #Inject on the constructor and/or fields of every class that should end up on your dependency graph and let Dagger do its thing.
I understand that constructor injection should be preferred whenever possible, but for theoretical understanding, I want to learn more about field and method injection.
Method injection apparently is very rare, and according to Jake Wharton, the only use-case for it is when you have to pass an instance of your dependent object to the dependency (because it might be not fully instantiated in the constructor yet).
Example for method injection:
#Inject
public void enableStreaming(Streaming streaming) {
streaming.register(this);
}
The field & method injection process into a dependent object can be triggered in 2 ways:
Either in combination with constructor injection, in which case
it is executed automatically after the constructor ran (no need to call inject on a component). This is what is happening in the example
above (I omitted the constructor, imagine it as being #Inject annotated)
Without constructor injection, when the object is already instantiated.
In this case, we need a members-injection method where
we pass the object. The fields/method will then be injected when we
call component.inject(object) This is most commonly used for
field-injection in activities and fragments.
What I am asking for, are examples for the opposite cases.
Do you have examples for when field injection is combined with
constructor injection?
Do yo you have examples for when method injection is not combined
with constructor injection (and therefore needs an explicit inject call)?
For both cases, I would like to know if there are situations when
the component.inject() method is called from the outside or from within the object and what are use-cases for this. Is there ever a
scenario where we call
ExampleObject exampleObject = new ExampleObject();
component.inject(exampleObject);
to execute field or method injection on exampleObject?
I don't have published or official examples handy, but all of the situations you described work fine. It is unusual for field injection to be combined with constructor injection, because the fields are necessarily non-final to work with field injection where they could be final if passed through a constructor. It is less-unusual to see method injection without constructor injection, for similar self-registration cases to the enableStreaming method you wrote above, but that is still somewhat of an unusual use-case.
Though field and method injection may take place within the method or class being injected, this would necessitate receiving a specific Component instance or a MembersInjector<T> for your class T, which is at least as much trouble to call as component.inject(exampleObject) in your third example above. After all, the whole point of dependency injection is to allow the caller to control the class's dependencies, so it is arguably a weakening of DI for the owning class to take control of whether and how its dependencies are provided.
The only cases I can think of where a class would manage its own injection is if your class wanted to conditionally inject itself—if (BuildOptions.FEATURE_X_ENABLED) { injector.inject(this); }—but many other patterns spring to mind that would manage that type of case better.
This is a Canonical Question because this is a common error with Dagger 2.
If your question was flagged as a duplicate please read this post carefully and make sure to understand what this error means and why it occured. If this post does not work for you make sure to include where and how you provide the mentioned classes and include the full error message in your question like the one here.
I tried to use a dependency with Dagger 2, but I receive the following error when I try to compile my project:
error: com.example.MyDependency cannot be provided without an #Inject constructor or from an #Provides-annotated method.
com.example.MyDependency is provided at
com.example.MyComponent.myDependency()
What does this mean and how can I fix it?
I have a component and tried to provide a dependency. My basic setup looks like this:
// this is the dependency I try to use
class MyDependency {}
#Component
interface MyComponent {
// I want to make it accessible to be used with my component
MyDependency myDependency();
}
tl;dr You forgot to either add an #Inject to your constructor so that Dagger can use Constructor Injection to provide the object, or you need some method in one of your Modules that creates or binds the object.
What's going on?
Have a good look at the error message: It states that you try to request a dependency but Dagger has no way to provide or create it. It simply does not know how to, because it cannot be provided without an #Inject constructor or from an #Provides-annotated method.
A close look at the error message shows the class (a) that you are trying to provide and the component (b) that needs it.
com.example.MyDependency (a) is provided at
com.example.MyComponent.myDependency() (b)
You have to make sure that (b) can create or provide (a) to fix your issue.
It looks a bit more complex if you tried to inject your dependency somewhere else, but you can still see the full stack of events—in this case a constructor injection missing a dependency. The class (a) that you are trying to provide and the location (b) where Dagger tried injecting it. It also tells you where that dependent class was created (c) and again the component (d) that failed providing (a).
com.example.MyDependency cannot be provided without an #Inject constructor or from an #Provides-annotated method.
com.example.MyDependency (a) is injected at
com.example.DependentClass.(dependency) (b)
com.example.DependentClass is provided at (c)
com.example.MyComponent.myDependency() (d)
The same applies here: Make sure that (d) knows how to provide (a) and you're good to go.
How do I fix this?
Have a look at the error as shown above. Make sure you understand where it occured and what you are trying to inject. Then tell Dagger how to provide your object.
an #Inject constructor
As the error states, you try to use MyDependency but MyComponent does not know how to do that. If we have a look at the example it becomes clear why:
class MyDependency {}
The class has no #Inject annotated constructor! And there is no other module in the component, so there is nothing Dagger could do.
If you want to use constructor injection you can just add an #Inject annotated constructor and are done. Dagger will see this constructor and know how to create your class.
class MyDependency {
#Inject
MyDependency() { /**/ }
}
That is all you have to do when you can make use of constructor injection.
from an #Provides-annotated method
The error message states a second option, which allows you to provide an object if you don't want—or can't—use constructor injection. You can also add a #Provides annotated method to a module and add this module to your component.
#Module
class MyModule {
#Provides
MyDependency provideMyDependency() {
return new MyDependency();
}
}
#Component(modules = MyModule.class)
interface MyComponent {
MyDependency myDependency();
}
This way Dagger can use your module to create and provide your dependency. It is a little bit more boilerplate than using Constructor Injection, but you will have to use Modules for everything that needs further setup or that does not have an annotated constructor, e.g. third party libraries like Retrofit, OkHttp, or Gson.
There are also other ways to provide a dependency from a component. A #SubComponent has access to its parents dependencies, and a component dependency can expose some of its dependencies to its dependent components. But at some point everything Dagger provides needs to either have an #Inject constructor or a Module providing it.
But I did add MyDependency!
Pay close attention to the details. You probably are using an interface when you are only providing the implementation, or try to use a parent class when Dagger only knows about the subclass.
Maybe you added a custom #Qualifier or used #Named("typeA") with it. To Dagger this is a completely different object! Double check that you actually provide and request the same dependency.
Read the error and make sure that you either have an #Inject annotated constructor, a module that has a #Provides method that provides that type, or a parent component that does.
What if I want to provide an implementation for my interface?
A simple example like the following shows how one class extends another:
class MyDependency extends MyBaseDependency {
#Inject MyDependency() { super(); }
}
This will inform Dagger about MyDependency, but not about MyBaseDependency.
If you have one class implementing an interface or extending a super class you have to declare that. If you provide MyDependency this does not mean that Dagger can provide MyBaseDependency. You can use #Binds to tell Dagger about your implementation and provide it when the super class is required.
#Module
interface MyModule {
#Binds
MyBaseDependency provideMyBaseDependency(MyDependency implementation);
}
My Guice is a little rusty (been 3 years) so bear with me. I have a custom API (#ContextSingleton) object that I need to #Inject into my various classes. This works fine when the target class extends from RoboActivity (or in my case, RoboSherlockActivity). However, when I want to inject it into a POJO, the injection fails and I get a null object.
Am I missing anything here? I tried writing a custom Provider for the API object (returning a new Api()), but the object creation graph isn't complete as any #Inject members within the API object is still null.
Right now I'm working around this by passing in the API object into POJOs instead of injecting it, but I'd like to eventually use #Inject for consistency.
I have this question, too. I think that we need to just use regular Guice for POJO cases. See my answer here: https://stackoverflow.com/a/24671352/189341