In this question I talk about Dagger2. Dagger2 consists basically of Components and Modules. Here is an example:
Assume I have a interface:
public interface MyCoolService {
void run();
}
and a possible implementation:
public class MyCoolServiceImpl {
@Override
void run() {}
}
I could link the implementation with the interface using Dagger2 generating:
@Component(modules = {MyModule.class})
@Singleton
public interface Component {
MyCoolService getMyCoolService();
}
and
@Module
public class MyModule {
@Provides @Singleton
MyCoolService provideMyCoolService() {
return new MyCoolServiceImpl();
}
}
This was a brief intro to Dagger2. Now assume I have the following interface:
public interface MySecondCoolService {
void doCoolStuff();
}
There is no implementation MySecondCoolServiceImpl of MySecondCoolService in code. Instead, I have an Annotations @JustForCoolStuff to mark fields and methods. I created an Annotation processor which collects all these Annotations and generates MySecondCoolServiceImpl which implements MySecondCoolService.
I the compiler knows the new interface MySecondCoolService before the annotation processor is running. So I could change my Component as:
@Component(modules = {MyModule.class})
@Singleton
public interface Component {
MyCoolService getMyCoolService();
MySecondCoolService getMySecondCoolService();
}
The problem is that I do not have an implementation yet in code and I do not know the name of the implementation of MySecondCoolService which will be generated by a annotation processor. Therefore, I cannot wire the interface with the correct implemantation in MyModule. What I can do is changing my annotation processor such that it generates a new module for me. My annotation processor could generate a module (MyGeneratedModule) like this:
@Module
public class MyGeneratedModule {
@Provides @Singleton
MySecondCoolService provide MySecondCoolService() {
return new MySecondCoolServiceImpl();
}
}
Again MyGeneratedModule is generated by an annotation processor. I do not have access to it before running the annotation processor also I do not know the name.
Here is the problem: The annotation processor somehow have to tell Dagger2 that there is a new module which Dagger2 should take into account. Since annotation processors cannot change files it cannot extend the @Component(modules = {MyModule.class}) annotation and change it into something like this: @Component(modules = {MyModule.class, MyGeneratedModule.class})
Is there a way to add MyGeneratedModule programmatically to the dagger2 dependency graph? How can my Annotation Processor tell Dagger2 that there should be a new wiring between an interface and an implementation as I have described above?
Foray: I know that something like that can be done in Google Guice and Google Gin. A project which does that is GWTP. There you have a Presenter:
public class StartPagePresenter extends ... {
@NameToken("start")
public interface MyProxy extends ProxyPlace<StartPagePresenter> {
}
...
}
which has a @NameToken annotation to a ProxyPlace interface. In your AbstractPresenterModule you wire the view with the presenter and the proxy:
public class ApplicationModule extends AbstractPresenterModule {
bindPresenter(StartPagePresenter.class,
StartPagePresenter.MyView.class, StartPageView.class,
StartPagePresenter.MyProxy.class);
...
}
As so can see no implementation of the MyProxy interface is given. The implementation created by a Generator (similar to annotation processor but for GWT). There Generator generates the implementation of StartPagePresenter.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() );
...
}
}
@Component(modules = {MyModule.class, MyGeneratedModule.class})in your code? - Tavian BarnesMyGeneratedModulewhich will be created. - user4788711GWT.create()but that won't change much things if your code is generated by an annotation processor. An annotation processor generates code; when a GWT generator both generates code and tells GWT to use it. You have to rethink your approach, not find workarounds. - Thomas Broyer