Reputation: 535
I am familiar with Spring dependency injection, but Dagger2 is new to me. I am trying to get a simple java application working but field injection does not work.
I have a class Main
, that depends on a class MainBusiness
which in turn depends on MainDao
.
MainBusiness
gets injected into Main
fine, but MainDao
does not get injected into MainBusiness
and throws a NullPointerException
.
Here is the MainDao
that implements an interface
IMainDao
public class MainDao implements IMainDao
{
@Inject
public MainDao()
{
}
public String getResource()
{
return "This is the resource you are looking for";
}
}
Here is the MainBusiness
that implements IMainBusiness
public class MainBusiness implements IMainBusiness
{
// package friendly field.
@Inject
IMainDao mainDao;
@Inject
public MainBusiness()
{
}
public String getResource()
{
return mainDao.getResource(); // throws NPE here.
}
}
Here is the AppModule
@Module
public class AppModule
{
/**
* Provides a singleton instance of the MainDao
*
* @return
*/
@Provides
@Singleton
public IMainDao providesMainDao()
{
return new MainDao();
}
/**
* Provides a singleton instance of the MainBusiness Class
*
* @return
*/
@Provides
@Singleton
public IMainBusiness providesMainBusiness()
{
return new MainBusiness();
}
}
The AppComponent
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent
{
/**
* @param main
*/
void inject(Main main);
}
And the Main
class
public class Main
{
@Inject
IMainBusiness mainBusiness;
public Main()
{
AppComponent dac = DaggerAppComponent.builder().build();
dac.inject(this);
}
public static void main(String args[])
{
Main main = new Main();
System.out.println(main.mainBusiness.getResource());
}
}
It throws an NPE on MainBusiness.getResource(MainBusiness.java:14)
What am I missing here? Appreciate any help I can get.
P.S This is a plain Java
application. It is not an Android
application.
Upvotes: 1
Views: 2837
Reputation: 34532
Field injection will inject the fields of the object you pass in. someComponent.inject(someObject)
will then inject the fields of someObject
, but it does not inject the dependencies transitively. Hence MainBusiness
will still have an uninitialized DAO.
If you call new MainBusiness();
yourself you can't expect Dagger to take care of it. You should use constructor injection, and not call new
yourself. Modules are for bindings, or additional setup, and should reduce the boilerplate of calling all the constructors yourself.
I took some liberty to switch to constructor injection and completely remove field injection, since it is not needed for your use case. (Maybe there's some typo, I did not compile it)
@Singleton
public class MainDao implements IMainDao
{
@Inject
public MainDao()
{
}
}
@Singleton
public class MainBusiness implements IMainBusiness
{
private IMainDao mainDao;
@Inject
public MainBusiness(IMainDao mainDao)
{
this.mainDao = mainDao;
}
}
@Module
interface AppModule {
@Binds IMainBusiness bindBusiness(MainBusiness impl);
@Binds IMainDao bindDao(MainDao impl);
}
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent
{
// -> no reason not to use constructor injection here as well
Main getMain(); // provision method
}
public class Main
{
private IMainBusiness mainBusiness;
// favor constructor injection
@Inject
public Main(IMainBusiness mainBusiness)
{
this.mainBusiness = mainBusiness;
}
public static void main(String args[])
{
AppComponent component = DaggerAppComponent.builder().build()
Main main = component.getMain();
System.out.println(main.mainBusiness.getResource());
}
}
I suggest that you have another look at some guides to make sure you understand the concepts, or you might be creating more work for yourself than necessary. I also wrote a post recently where I try to clear up some misconceptions about Dagger.
Upvotes: 7