In a project I am working on I have 2 classes that are highly dependent on one another:
@Singleton
class WorkExecutor {
@Inject Provider<ExecutionServices> services;
...
public void execute(Work w){
w.execute(services.get());
...
}
...
}
class ExecutionServicesImpl implements ExecutionServices {
@Inject WorkExecutor executor;
...
}
The idea is that when executing a work, the work has access to several services - one of them is the executor itself so that a work will be able to execute sub works.
As one can see, there is a circular dependency here, but one that I found very hard to break.
The main problem is that the WorkExecutor does not actually need an instance of ExecutionServices object at graph-constructing time but only a provider to be used later. sadly, Dagger does not know that the WorkExecutor will not call the ExecutionServices provider from the constructor of the class so it guesses that ExecutionServices depends on WorkExecutor and vice versa.
One possible solution that I found is to define a module and component in the following way:
interface DelayedProvider<T> extends Provider<T>{}
@Module
class AppModule {
Provider<ExecutionServices> delayedProvider = null;
@Provides DelayedProvider<ExecutionServices> provideDelayed() {
return () -> delayedProvider.get();
}
@Provides @Named("late-binding-conf") Void latebindingConf(Provider<ExecutionServices> eager){
this.delayedProvider = eager;
return null; //notice we returning Void and not void
}
}
@Component(modules=AppModule.class)
interface AppComponent {
App app();
@Named("late-binding-conf") Void configureLateBinding();
}
and then I modifies the original classes to be:
@Singleton
class WorkExecutor {
@Inject DelayedProvider<ExecutionServices> services;
...
public void execute(Work w){
w.execute(services.get());
...
}
...
}
class ExecutionServicesImpl implements ExecutionServices {
@Inject WorkExecutor executor;
...
}
And then in order to create my app I have to do:
AppComponent acomp = DaggerAppComponent.create();
App = acomp.app();
acomp.configureLateBinding();
But I am not sure this is the proper course of action - Is there a better way?