I'm very new to Dagger 2 and I'm trying to get this basic example working with some minor modifications.
This is what I have so far:
Component class
#Component(modules = {MyModule.class})
public interface MyComponent {
void inject(Object object);
}
Module class
#Module
public class MyModule {
#Provides
#Singleton
public Retrofit getRetrofit(){
return new Retrofit();
}
}
Static Injector
public class MyStaticInjector {
private static MyComponent di;
public static void inject(Object object){
if(di == null){
di = DaggerMyComponent.builder().build();
}
di.inject(object);
}
}
The problem is that whenever I do
MyStaticInjector.inject(this);
the annotated fields are still null. I suspect the problem is with the type Object in the interface method. In the example, there's an Activity instead. But I need to use DI in classes that are not activities.
Can anyone help me? Thank you.
Object has no #Inject annotated fields. Thus the injection works just fine—it just has nothing to inject.
You will have to use your actual classes with inject(MyClass) instead of Object, so that the code can be generated and fields can be injected.
Dagger generates source code at compile time. If it does not know about the actual class, it cannot create code for it.
Related
I want to use Dagger in a project currently configured with Guice. I'm still very new to the concepts of DI, but I see that both Guice and Dagger use #Inject and #Provides notations. I have some understanding of the #Module and #Component annotations and how to set them up, but I'm wondering if the #Inject and and #Provides can basically be left as they are?
For example, let's say I have this in Guice:
public class ModuleA extends AbstractModule {
#Inject
public ModuleA() {
...
}
#Provides
#Singleton
protected InterfaceX() {
...
}
}
Could the following dagger implementation work the same, assuming there is also a component etc?
#Module
public class ModuleA {
#Inject
public ModuleA() {
...
}
#Provides
#Singleton
protected InterfaceX() {
...
}
}
One thing that confused me was that #Provides is used in Dagger to bind implementations to interfaces, and I'm not sure if that's what it is used for in Guice.
Again, I'm pretty new to this so any clarification would be really appreciated. Thanks!
NOTE: Have not used Dagger but can clarify on Guice side.
#Provides in Guice is for informing the Guice injector about which method to use to for creating the asked object at build time.
for eg : class Parent has implementation in 2 sub classes Child1 and Child2
Now you want to have a logic which defines when to inject Child1 and when to inject child2. This logic can be written in a method which can become the provider for Parent class impl. and to declare this provider method, #Provides annotation is used
class Parent {}
class Child1 extends Parent {}
class child2 extends Parent {}
GuieModule {
#Provides
Parent getParent() {
if(something)
return new Child1();
else
return new child2();
}
}
I am looking into Dagger 2 (Java) right now and came across an issue right upon the start. Sadly, I was not able find a anything yet in the Dagger 2 Documentation or on Stackoverflow about it, so if you guys know some resources I would really appreciate it.
I prepared a minimal example within this repository here to explain whats my issue: https://github.com/stackoverflow-samples/dagger2-dependency-cycle
So we got an Application class that should be constructed
public class Application {
#Inject
public Application(SomeDependency one) {
}
public static void main(String[] args) {
DaggerApplicationComponent.create().build();
}
}
... with a dummy dependency
public class SomeDependency {
#Inject
public SomeDependency() {
}
}
And of course the Dagger classes/interfaces ...
.. a component interface:
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
Application build();
}
.. and a module:
#Module
abstract class ApplicationModule {
#Provides
static SomeDependency provideDepdendencyOne() {
return new SomeDependency();
}
}
What I dont get is why Dagger forces me to register SomeDepdendency with #Provides annotation and does not allow to register it via #Binds:
#Binds
abstract SomeDependency bindDepdendencyOne(SomeDependency one);
Whenever I change the code from #Provides to #Binds it gives me the following errors:
[Dagger/DependencyCycle] Found a dependency cycle:
io.github.codejanovic.dagger2.example.SomeDependency is injected at
io.github.codejanovic.dagger2.example.ApplicationModule.bindDepdendencyOne(one)
io.github.codejanovic.dagger2.example.SomeDependency is injected at
io.github.codejanovic.dagger2.example.Application(one)
io.github.codejanovic.dagger2.example.Application is provided at
io.github.codejanovic.dagger2.example.ApplicationComponent.build()
Being unable to #Bind an implementation makes absolutely no sense to me. What do I oversee?
Thanks in advance.
You're wrong in assuming that you need #Binds or #Provides in the first place. You can and should be using constructor injection—not the pattern, but the Dagger generates the code for me kind.
You already have the constructor annotated with #Inject, thus Dagger knows about the class and how to create it. There's nothing else to do.
public class SomeDependency {
#Inject
public SomeDependency() {
}
}
You don't need any #Provides, no #Binds, not even a #Module for this simple use case of yours. Your example should work right out of the box since both constructors are annotated with #Inject.
#Component
public interface ApplicationComponent {
Application build();
}
If you need to specify a scope you can add it on the class.
#Provides should be used for code that you can't use constructor injection for, or that needs additional setup. Of course you can create all the objects manually (as you're doing in your example) but this has no real benefit and will just produce a lot of boilerplate that can be avoided.
#Binds is to be used with implementations that you need to bind to an interface. Optimally you'd use constructor injection for the implementation as well, but you can as well add it to the component builder (#BindsInstance) or create it in a #Provides annotated method.
#Binds MyInterface bindMyImplementation(MyImplementation implementation);
If your class is marked with an #Inject constructor:
public class SomeDependency {
#Inject // <----
public SomeDependency() {
}
}
Then you need #Binds (or #Provides) only if you need to "bind" it as an implementation of an interface, or at least a different type than its concrete type.
Also, if your object has an #Inject constructor, you would not need to instantiate it in the module, because Dagger already knows how to instantiate it.
So to fix your code, all you need to do is:
// #Module
// abstract class ApplicationModule {
// #Provides
// static SomeDependency provideDepdendencyOne() {
// return new SomeDependency();
// }
// }
Solved.
I have a question with dagger2,
If I provide #Singleton with ApplicationComponent but don't instantiate the object using #Inject in some class. Does the object get instantiate or it will get instantiated when it is #Inject in some class?
For example, in below code, does test instantiated on main2?
#Singleton
public class Test {
#Inject
public Test() {
}
}
public class main() {
#Inject Test test;
public void start() {
DaggerComponent.create().inject(this);
}
}
public class main2() {
public void start() {
DaggerComponent.create().inject(this);
}
}
In above case , Test will be instantiated in class Main by the instance of the DaggerComponent in that class .
But in class Main2 , Test will not be instanciated unless an explicit #Inject annotation is marked on a property of type Test .
Also , note that in case above , if you need singleton instance of class Test in both class Main and Main2 , use the same DaggerComponent instance to inject Test object in both class . As you are separately instanciating DaggerComponent in both classes , you will get separate instances of class Test in Main and Main2.
If you want to know how dagger uses scopes behind the scenes, read the Dagger generated code . I have written an article on medium regarding how dagger scopes works internally. Follow this if you want to . How Dagger scopes work internally
It will get instantiated when it is injected in some class.
You can check the generated code by dagger for the inject(main2) method for your DaggerComponent class and it will be empty like this:
#Override
public void inject(main2 clazz) {}
Whereas the inject(main) method will have calls to inject the field (after creating an instance of it).
private IRequirementDao requirementDao;
#Override
public void saveAllRequirements(List<Requirement> requirementsList) {
requirementDao.saveAllRequirements(requirementsList);
}
this call to the saveAllRequirements method throwing null pointer exception
where IRequirementDao is a interface with some methods shown bellow
public interface IRequirementDao {
public void saveRequirement(Requirement requirement);
public List<Requirement> getAllRequirementsCreatedBy(String createdBy);
public List<Requirement> getAllRequirementsCreatedAfter(Date createdTs);
public List<Requirement> getAllRequirementsForProject(long projectKey);
public List<Requirement> getAllRequirementsAsofDt(Date asOfDt);
public void saveAllRequirements(List<Requirement> requirementsList);
public List<Requirement> getRequirementsWithTracebilityId(String tracebilityId);
}
Please anyone can help me out.
Thanks in advance
You've declared an object of type IRequirementDao, but according to your code it is neither initialised nor injected.
If you're using some kind of dependency injection, such as Spring or Java EE, you can annotate this field with #Resource in order to have it injected - provided that there is at least one implementation of this class available.
If you're not using dependency injection, you'll need to provide an object yourself by assigning an IRequirementDao implementation to your field, like so:
this.requirementDao = new RequirementDaoImpl(); // or whatever the name of your DAO implementation.
That is an interface. You need to implement that interface in a class and then call the saveAllRequirements method from your class.
To implement an interface use this format:
public class ClassA implements IRequirementDao{
}
It will then force you to write your implementation of each method in the interface. Then in your other class you need to initialise your class which implemented the interface:
public class ClassB {
public ClassB{
ClassA a = new ClassA();
}
public void saveAllRequirements(List<Requirement> requirementsList) {
requirementDao.saveAllRequirements(requirementsList);
}
}
In most cases I have a lot of components which are having the same classes to be injected by an OSGi Declarative Service. The services will be used to execute some logic which is the same for all derived components. Therefore to avoid duplicated code it would be the best to use abstract classes. Is there any possibility to move the DI reference methods (set/unset) to an abstract class. I'm using Bnd.
For Example:
#Component
public class B implements IA {
private ServiceC sc;
#Reference
public void setServiceC(ServiceC sc) {
this.sc = sc;
}
public void execute() {
String result = executeSomethingDependendOnServiceC();
// do something with result
}
protected String executeSomethingDependendOnServiceC() {
// execute some logic
}
}
#Component
public class D implements IA {
private ServiceC sc;
#Reference
public void setServiceC(ServiceC sc) {
this.sc = sc;
}
public void execute() {
String result = executeSomethingDependendOnServiceC();
// do something different with result
}
protected String executeSomethingDependendOnServiceC() {
// execute some logic
}
}
I want to move the setter for ServiceC and the method executeSomethingDependendOnServiceC() to an abstract class. But how does it look like in OSGi in connection with Bnd annotation. Just annotate the class with #Component is not working, because A and D will create different instances of the abstract class and the #Component is alsp creating an instance.
Maybe someone experience the same problem and give me some advices how a workaround could look like. At least a best practice solution would be fine as well :)
The DS annotations must be on the class being instantiated for the component. Annotations on super classes are not supported. There is a proposal to change the in a future spec release.
What you can do is move the method to the super class, but you will need to trivially override the method in the subclass so that you can annotate it in the subclass.