В этом вопросе я расскажу о Dagger2. Dagger2 состоит в основном из компонентов и модулей. Вот пример:
Предположим, у меня есть интерфейс:
public interface MyCoolService {
void run();
}
и возможная реализация:
public class MyCoolServiceImpl {
@Override
void run() {}
}
Я мог бы связать реализацию с интерфейсом с помощью создания Dagger2:
@Component(modules = {MyModule.class})
@Singleton
public interface Component {
MyCoolService getMyCoolService();
}
и
@Module
public class MyModule {
@Provides @Singleton
MyCoolService provideMyCoolService() {
return new MyCoolServiceImpl();
}
}
Это было краткое введение в Dagger2. Теперь предположим, что у меня есть следующий интерфейс:
public interface MySecondCoolService {
void doCoolStuff();
}
В коде отсутствует реализация MySecondCoolServiceImpl
of MySecondCoolService
. Вместо этого у меня есть аннотации @JustForCoolStuff
для обозначения полей и методов. Я создал обработчик аннотации, который собирает все эти аннотации и генерирует MySecondCoolServiceImpl
, который реализует MySecondCoolService
.
I компилятор знает новый интерфейс MySecondCoolService
до запуска обработчика аннотаций. Поэтому я мог бы изменить свой Компонент как:
@Component(modules = {MyModule.class})
@Singleton
public interface Component {
MyCoolService getMyCoolService();
MySecondCoolService getMySecondCoolService();
}
Проблема заключается в том, что у меня еще нет реализации в коде, и я не знаю имя реализации MySecondCoolService
, которое будет создано обработчиком аннотаций. Поэтому я не могу подключить интерфейс с правильной реализацией в MyModule
. Что я могу сделать - это изменить мой обработчик аннотации, чтобы он создавал для меня новый модуль. Мой обработчик аннотации может генерировать модуль (MyGeneratedModule
) следующим образом:
@Module
public class MyGeneratedModule {
@Provides @Singleton
MySecondCoolService provide MySecondCoolService() {
return new MySecondCoolServiceImpl();
}
}
Снова MyGeneratedModule
генерируется обработчиком аннотации. У меня нет доступа к нему, прежде чем запускать обработчик аннотации, также я не знаю этого имени.
Вот проблема: Обработчик аннотации каким-то образом должен сказать Dagger2, что есть новый модуль, который должен учитывать Dagger2. Поскольку обработчики аннотаций не могут изменять файлы, они не могут расширять аннотацию @Component(modules = {MyModule.class})
и изменить ее на что-то вроде этого: @Component(modules = {MyModule.class, MyGeneratedModule.class})
Есть ли способ добавить MyGeneratedModule
программно к графику зависимости dagger2? Как мой обработчик аннотации сообщает Dagger2, что должна быть новая проводка между интерфейсом и реализацией, как я описал выше?
Foray: Я знаю, что что-то подобное можно сделать в Google Guice и Google Gin. Проект, который делает это GWTP. Там у вас есть Ведущий:
public class StartPagePresenter extends ... {
@NameToken("start")
public interface MyProxy extends ProxyPlace<StartPagePresenter> {
}
...
}
который имеет аннотацию @NameToken
к интерфейсу ProxyPlace
. В вашем AbstractPresenterModule
вы подключите представление с презентатором и прокси:
public class ApplicationModule extends AbstractPresenterModule {
bindPresenter(StartPagePresenter.class,
StartPagePresenter.MyView.class, StartPageView.class,
StartPagePresenter.MyProxy.class);
...
}
Как видно, реализация интерфейса MyProxy
не указана. Реализация, созданная генератором (аналогично процессору аннотации, но для GWT). Генератор генерирует реализацию StartPagePresenter.MyProxy
и добавляет его в систему guide/gin:
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() );
...
}
}