Dagger 2 instantiation on application component - java

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).

Related

Why does Dagger 2 force me to use #Provides instead of #Binds

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.

Dagger 2 Dependency Injection not working

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.

Mock class without PowerMock in arquillian Test

I would like to now, if it is possible to mock a class like
public class MyClass{
...
}
Our business logic create this object with new myClass() somewhere in the code and therefore I don't have access to the created object to mock those methods. Is there a way to replace the whole class or to overwrite those methods. I'm using mockito and I only found examples to do this like
#Test
public void myTest{
MyClass myClass = Mockito.mock(MyClass.class);
Mockito.when(myClass.myMethod()).thenReturn("hello World");
...
}
We can't use PowerMock because it isn't compatible with our test environment.
Any suggestions are welcome.
Sorry, i see only two hardcore solutions:
Make Powermock working by using PowerMockRule and PowerMock Rule Agent:
Getting javassist not found with PowerMock and PowerRule in Junit with Mockito
or
Use Java Reflection to set the mocked object to MyClass: Is it possible in Java to access private fields via reflection
I found a passable way to achieve my requirement.
I converted MyClass to a bean, just add annotation #Dependent.
#Dependent
public class MyClass{
public Integer someMethod(){
return 100;
}
}
I use MyClass in business logic like that
public class BusinessClass{
#Inject
MyClass myClass
public Integer doSomething(){
return myClass.someMethod();
}
}
After this change I'm able to mock the class in my test with annotation #Specializes
#Specializes
#Dependent
public class MyClassMock extends MyClass
{
#Override
public Integer someMethod(){
return 23; // return my mocked value
}
}
MyClass will be automatically replaced with MyClassMock in testenvironment.

Spring autowried in Abstract class construtor

I have a scenario where autowired is null when called in the constructor of an abstract class like this :
public abstract class AbstractClass{
#Autowired
#Qualifier("proId")
protected Prop prop;
public AbstractClass(){
prop.getName();
The above throws NullException on deployment.
But the following works when the autowired property called after instantiating
public abstract class AbstractClass{
#Autowired
#Qualifier("proId")
protected Prop prop;
public void Init(){
prop.getName();
}
}
public class DefaultClass extends AbstractClass(){
...
#autowired
DefaultClass dc ;
...
dc.Init();
How can I get the first case to work ?
You can't. Injection can only happen after an object has been created (or during construction with constructor injection). In other words, when prop.getName() is called inside the abstract class constructor, the field is still null since Spring hasn't processed it.
Consider refactoring your code so that your abstract class has a constructor that accepts a Prop argument and use constructor injection
public AbstractClass(Prop prop) {
this.prop = prop;
prop.getName();
}
...
#Autowired
public DefaultClass(Prop prop) {
super(prop);
}
Do you know object creation life-cycle in Java?
Spring doesn't do any magic about that.
There are multiple phases when using Spring for creating beans
an object is instantiated using the constructor
dependencies are injected into bean (obviously except for constructor dependencies which are passed through the object in first phase)
objects #PostConstruct (or InitializingBean) methods are called.
Remember that before constructor there is no instance of your bean, so Spring can not wire anything in it!

How to create a dummy instance unsing jmockit?

For a test I like to create a new instance of ComplicatedClass . In reality it's very complicated to crate this instance, but I don't need the real constructor to run nor any of it's data. All I need is an object of ComplicatedClass. How can I do that?
public class ComplicatedClass {
public ComplicatedClass(/* lots of dependencies */) {
}
}
#Test
public class SomeTest {
public void test1() {
ComplicatedClass complicatedInstance = /* new ComplicatedClass(); /*
AnotherClass ac = new AnotherClass(complicatedInstance);
/* ... */
}
}
#Tested annotation does this:
#Tested ComplicatedClass complicatedInstance;
That's it. Please note that the above won't do any mocking. It is just convenient way of creating instances without calling consturctors, etc.
If you want ComplicatedClass to be mocked, use #Mocked annotation:
#Mocked ComplicatedClass complicatedInstance;
In this case, you also get your instance automatically created, but the instance is mocked.
#Tested internally instantiates the class object.
But in case of Junit test case writing of singleton class how #Tested internally creates instance because for singleton private constructor is there.

Categories