Java – using annotations to handle delayed binding to dagger2 diagram
On this issue, I talk about dagger 2 Dagger 2 basically consists of components and modules Here is an example:
Suppose I have an interface:
public interface MyCoolService { void run(); }
And may implement:
public class MyCoolServiceImpl { @Override void run() {} }
I can use dagger2 to link the implementation to the interface:
@Component(modules = {MyModule.class}) @Singleton public interface Component { MyCoolService getMyCoolService(); }
and
@Module public class MyModule { @Provides @Singleton MyCoolService provideMyCoolService() { return new MyCoolServiceImpl(); } }
This is a brief introduction to dagger 2 Now suppose I have the following interface:
public interface MySecondCoolService { void doCoolStuff(); }
Mysecondcoolservice does not implement mysecondcoolserviceimpl. In the code Instead, I have an annotations @ justforcoolstuff to mark fields and methods I created an annotation processor that collects all these annotations and generates a mysecondcoolserviceimpl that implements mysecondcoolservice
The compiler knows the new interface mysecondcoolservice before the annotation processor runs So I can change my component to:
@Component(modules = {MyModule.class}) @Singleton public interface Component { MyCoolService getMyCoolService(); MySecondCoolService getMySecondCoolService(); }
The problem is that I haven't implemented it in the code. I don't know the implementation name of mysecondcoolservice, which will be generated by the annotation processor Therefore, I cannot use the correct implementation of the connection interface in mymodule What I can do is change my annotation processor to generate a new module for me My annotation processor can generate a module (mygenerated module), as shown below:
@Module public class MyGeneratedModule { @Provides @Singleton MySecondCoolService provide MySecondCoolService() { return new MySecondCoolServiceImpl(); } }
Again, mygeneratedmodule is generated by the annotation processor Before running the annotation processor, I had no access, and I didn't know the name
Here's the problem: the annotation processor has to tell dagger2 that there is a new module that dagger2 should consider Because the annotation processor cannot change the file, the @ component (modules = {mymodule. Class}) annotation cannot be extended and changed as follows: @ component (modules = {mymodule. Class, mygeneratedmodule. Class})
Is there a way to programmatically add mygeneratedmodule to the dagger2 dependency diagram? How does my annotation processor tell dagger2 that, as mentioned above, there should be a new wiring between the interface and the implementation
Raid: I know such things can be done in Google Guice and Google gin One such project is gwtp You have a Presenter:
public class StartPagePresenter extends ... { @NameToken("start") public interface MyProxy extends ProxyPlace<StartPagePresenter> { } ... }
It has a @ nametoken comment on the proxyplace interface In your abstractpresentermodule, you associate views with presenters and delegates:
public class ApplicationModule extends AbstractPresenterModule { bindPresenter(StartPagePresenter.class,StartPagePresenter.MyView.class,StartPageView.class,StartPagePresenter.MyProxy.class); ... }
Therefore, you can see that the implementation of myproxy interface is not given The implementation created by the generator (similar to the annotation processor, but for GWT) Generator generates startpagepresenter Implement myproxy and add it to the guide / gin system:
public class StartPagePresenterMyProxyImpl extends com.gwtplatform.mvp.client.proxy.ProxyPlaceImpl<StartPagePresenter> implements buddyis.mobile.client.app.start.StartPagePresenter.MyProxy,com.gwtplatform.mvp.client.DelayedBind { private com.gwtplatform.mvp.client.ClientGinjector ginjector; @Override public void delayedBind(Ginjector baseGinjector) { ginjector = (com.gwtplatform.mvp.client.ClientGinjector)baseGinjector; bind(ginjector.getPlaceManager(),ginjector.getEventBus()); presenter = new CodeSplitProvider<StartPagePresenter>( ginjector.getbuddyismobileclientappstartStartPagePresenter() ); ... } }
Solution
Yes Use a constructor parameter in your module
@Module public class MyModule { private final MyCoolService serviceImpl; public MyModule(MyCoolService serviceImpl) { this.serviceImpl = serviceImpl; } @Provides @Singleton MyCoolService provideMyCoolService() { return new MyCoolServiceImpl(); } }
When you build a graph, serviceimpl is initialized:
DaggerComponent.builder().myModule(new MyModule(serviceImpl)).build();