I am using dagger 2 for dependency injection and got stuck with field injection. Below is the complete scenario with code sample:
Let's say we have a class A which depends on a library B
class A {
#Inject
B b;
}
Module for B:
#Module
public class BModule {
#Provides
#Singleton
public B provideB() {
return new C.methodA();
// C - static class; C.methodA returns B
}
}
But when I try to use b in class A then I get null pointer exception but if I do the same using constructor injection then it works perfectly.
I can assure that component and other dependencies are fine as the constructor part works correctly.
A is a dependency of some other class (let's call X) and A is being initialized using constructor injection (tested). Also, X is being injected as void inject(X x);
I have 2 questions:
Is there anything I am missing out for field injection due to which it is not being injected?
I am able to successfully compile the code and get runtime exception, but dagger2 is compile-time DI then why is it unable to catch this while compiling?
P.S.: I have just shared a part of the code as there are multiple dependencies, so just trying to explain the scenario. Let me know if the question/scenario is still unclear or needs more info.
Thanks.
Field injection in dagger is a bit more complicated than constructor injection. When you use constructor injection like this
class A {
#Inject
public A(B b) {}
}
and you have provider for class B
#Module
class DaggerModule {
#Provides
B provideB() {}
}
now dagger will know how to create instance of A and pass it required constructor parameter. So everything is fine, compile successfully and works perfect.
But if we speak about field injection
class A {
#Inject
B b;
}
and have somewhere provider for B, dagger can't know how to create A instance and when inject b property (in case of manually creating instance of A by hand). To make it work you need write special method in component
#Component(DaggetModule.class)
interface DaggerComponent {
void inject(A a);
}
and somewhere in code
A a = new A();
DaggerComponent component = //TODO getDaggerComponent()
component.inject(a);
After that b property will be initialized and available for later usage. Hope, it's clear now how to make field injection work.
Related
Tech Stack: Java-11, Spring, SpringBoot
I am trying to re-create a scenario, where Field Injection in Spring would cause Circular Dependency Error
Class A is injected to Class B
Class B is injected to Class A
At Spring Run time, I was expecting the Circular Injection Error to come but it didnt
In class CallingService, I am trying to call class A's method which refers to class B's method. But that also didnt create the Circular Dependency Error.
Class A
#Service
#Data
public class A {
#Autowired B b;
String str = "B";
public void methodA() {
System.out.println(b.str); // referring to B's instance
}
}
Class B
#Service
#Data
public class B {
#Autowired A a;
String str = "B";
public void methodB() {
System.out.println(a.str); // referring to A's instance
}
}
Class CallingService <---- (trying to create Circular Dependency Error in this class)
#Service
#Data
public class CallingService {
#Autowired A a;
public void methodCalled() {
System.out.println(a.str); // This printed successfully as "A"
}
}
My Queries:
Circular Dependency is expected at run-time or while reference-time(when code is referred while running) in Field Injection [This is clear now. It will come at SPRING's]
What changes do I do to my code to create Circular Dependency Error here using Field Injection
I am actually insisting for using Field Type Injection instead of Constructor Type Injection at my office project, as the prior is quick and eliminates verbose code.
Went through few blogs which were recommending Constructor-Dependency but found most of the points lame. Only concerning one was of Circular Dependency Error. So trying to recreate the same as a POC.
Asking your questions:
Circular dependency error is avoided with Setter or Field injection. The reason being that Spring creates the beans, but the dependencies are not injected until they are needed. In Constructor injection it will ever be a runtime error, never compile time.
Use Constructor injection. But you only get the error on runtime.
Constructor injection is way more unit test friendly than Setter or Field injection, so I also recommend you using Constructor injection.
I am having problems injecting a generic type interface. Not sure how to do this or google it since I don't know the exact terms to search for. Sorry if i'm completely wrong just getting started with dagger.
Basically I have a use case class
public class LoadConversations<C extends IConversation>
extends UseCase<List<C>, LoadConversations.Type> {
private final IConversationRepository<C> messageRepository;
#Inject LoadConversations(#NonNull IConversationRepository<C> messageRepository) {
this.messageRepository = messageRepository;
}
....
public enum Type {
ALL, NEWER, OLDER
}
}
With IConversationRepository being an interface.
public interface IConversationRepository<C extends IConversation> {
Observable<List<C>> conversations(LoadConversations.Type params);
}
IConversation being a blank interface and ConversationModule where i provide the IConversationRepository.
Im having problems injecting with the following code. Am i missing something or doing something completey wrong. Thanks in advance.
Trying to provide as follows:
#Provides IConversationRepository<Conversation> provideConversationRepository(
ConversationRepository conversationRepository) {
return conversationRepository;
}
And I'm trying to inject this to my presenter as
private final LoadConversations<Conversation> loadConversations;
#Inject public ConversationListPresenter(LoadConversations<Conversation> loadConversations) {
this.loadConversations = loadConversations;
}
Implementation of ConversationRepository
public class ConversationRepository implements IConversationRepository<Conversation> {
#Override public Observable<List<Conversation>> conversations(LoadConversations.Type params) {
....
}
}
Error Log:
Error:(15, 10) error: com.rbttalk.android.data.repository.ConversationRepository cannot be provided without an #Inject constructor or from an #Provides-annotated method.
com.rbttalk.android.data.repository.ConversationRepository is injected at
com.rbttalk.android.di.module.sub_modules.ConversationModule.provideConversationRepository(conversationRepository)
com.rbttalk.android.domain.repository.IConversationRepository<com.rbttalk.android.domain.models.Conversation> is injected at
com.rbttalk.android.domain.usecase.conversation.LoadConversations.<init>(arg0, …)
com.rbttalk.android.domain.usecase.conversation.LoadConversations<com.rbttalk.android.domain.models.Conversation> is injected at
com.rbttalk.android.ui.main.conversation.ConversationListPresenter.<init>(loadConversations)
com.rbttalk.android.ui.main.conversation.ConversationListPresenter is injected at
com.rbttalk.android.ui.main.conversation.ConversationListFragment.userListPresenter
com.rbttalk.android.ui.main.conversation.ConversationListFragment is injected at
com.rbttalk.android.di.component.ConversationComponent.inject(conversationListFragment)
You're very close! The error message says it all:
com.rbttalk.android.data.repository.ConversationRepository cannot be provided without an #Inject constructor or from an #Provides-annotated method.
Note that this is not IConversationRepository; you've provided a binding for that with your #Provides method (which you can eventually consider converting to a #Binds method). However, that #Provides method has a parameter, ConversationRepository, which effectively asks Dagger to create an instance of that concrete ConversationRepository type for you. You've made that binding correctly, but now Dagger needs to instantiate ConversationRepository for you, and it simply doesn't know how.
You'll need to create an #Inject-annotated constructor for ConversationRepository using the annotation type javax.inject.Inject, even if it just looks like this:
#Inject ConversationRepository() {}
This allows Dagger to know that yes, it is safe to call that constructor. (This differs from Guice, which was willing to call a public parameterless constructor including the default constructor provided by Java.) Though you are welcome to accept injector-provided parameters in that annotated constructor (which might be nice if your repository has dependencies, because then you can keep the fields final), you may also choose to simply annotate some fields with #Inject and let the injector populate those after creation.
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);
}
Let's say I have the following classes and dagger module
public class Base implements IBase {
private IDependency dependency; //IDependency is an interface
Base(IDependency dependency) {
this.dependency = dependency
}
}
public class SubClass extends Base implements ISubclass {
Base(IDependency dependency) {
super(dependency)
}
}
#Module
public class MyModule {
// Let's assume some other class use SubClass and requires this
#Provides
ISubclass providesSubclass(IDependency dependency) {
return new SubClass(dependency);
}
}
If I add a new parameter to Base constructor, I'll have to go to MyModule and modify provides method to include this new parameter (besides obviusly chaging Base and Subclass constuctors). It seems to me that using propery injection I don't have this problem since I'm not using any constructor.
My feeling is that I might be doing something wrong or I have some concept wrong. I prefer constructor injection over property injection but right now I have to add a constructor parameter to a base class used by 40 other classes and not only I have to modify those 40 classes constructors, I also have to modify modules to reflect new constructors parameters.
Am I missing something? Am I correct if I say that doing constructor injection I'll write much more less code and maintenance will be easier?
Yes, you are missing some awesome feature: You can still use constructor injection in this case! And you don't even have to write it yourself.
If all of the dependencies can be provided, dagger can and will create the object for you. Given that you can provide IDependency you just need to modify your code like the following:
public class SubClass extends Base implements ISubclass {
#Inject // Don't forget the annotation!
public Base(IDependency dependency) {
super(dependency)
}
}
#Module
public class MyModule {
#Provides
ISubclass providesSubclass(SubClass subclass) {
return subclass;
}
}
You provide the interface, yet you depend on your implementation to provide it. Dagger will resolve this, and you can merrily add as many parameters to the constructor as you like. (Apart from the obvious changes to the actual constructors you already pointed out)
Don't forget the #Inject annotation!
I have an interface I with method m and two concrete implementations A and B.
public interface I{
public void m();
}
public class A implements I{
public void m(){
//
}
}
public class B implements I{
public void m(){
//
}
}
I want to know when I inject I which of the two methods will be executed
#EJB
private I service;
///
service.m();
/////
None of them, it will become into an error since the application server doesn't know which implementation to use. To avoid this, just provide the id of the class implementation, which by default is the same name of the class but starting with lower case:
//uncomment one of these
//#EJB(name="a")
//#EJB(name="b")
private I service;
None of them. The code will compile, but you won't be able to deploy it on your application server. Without specifing type of injected class, you will get an Exception similar to this:
org.jboss.weld.exceptions.DeploymentException:WELD-001409 Ambiguous dependencies
for type [...] with qualifiers [...] at injection point [...]. Possible dependencies
[...] with qualifiers [...], Managed Bean [...] with qualifiers [...]
Container (i.e. your application server) won't be able to recognize which field do you really want to inject (A or B). It cannot just guess it out of thin air. To avoid this kind of errors, provide it with annotation (called qualifier) specifying whether you want to inject class A or class B. If you want an example, you should see this article.