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?
I don't suspect OP will like this, as you want a way to make something 'wrong', work 'right'. That can't really be. Whenever you encounter a circular dependency, the "right" solution is to refactor to remove that dependency.
In your case, WorkExecutor is a singleton so it probably needs to remain as is. ExecutionServicesImpl should then be modified to remove the dependency on WorkExecutor. Without knowing the specifics of the code, one can't say too much more. However, having an ExecutionService be independent from it's "worker" is reduced coupling and likely a very good thing in the long run.
why does ExecutionServicesImpl depend on WorkExecutor?
Show more core, ExecutionServices sounds like a Singleton too, why does it depend on each other to work correctly?
WorkExecutor sounds like something that you can pass to the ExecutionService as WorkExecutor will be injected somewhere else, maybe the one that uses the Service.
I dont know, show more code and probably that's the answer, it looks complex.
I ran into a situation in a Swing project where a third-party object depended on a JFrame, and the JFrame depended on the third-party object to produce its content pane. I came up with this solution, but ultimately decided to close the loop in my main method after the object graph was constructed. Basically, I created two named JFrame providers, the second depending on the first and returning the same instance:
#Provides
#Singleton
#Named("DO_NOT_INJECT")
JFrame mainWindowIncomplete() {
return new JFrame(); // after setting it up
}
#Provides
#Singleton
CControl dockControl(#Named("DO_NOT_INJECT") JFrame mainWindow) {
return new CControl(mainWindow);
}
#Provides
#Singleton
#Named("MAIN_WINDOW")
JFrame mainWindow(#Named("DO_NOT_INJECT") JFrame mainWindow, CControl dockControl) {
mainWindow.add(dockControl.getContentArea());
return mainWindow;
}
For this to work, the second provider would have to be used at least once. You can ensure this by adding a package-private qualifier to the first one as described in this answer.
Related
I have a BIG Android app that needs to run different code for depending on the OS version, the manufacturer, and many other things. This app however needs to be a single APK. It needs to be smart enough at runtime to determine which code to use. Until now we have been using Guice but performance issues are causing us to consider migrating to Dagger. However, I've been unable to determine if we can achieve the same use case.
The main goal is for us have some code that runs at startup to provide a list of compatible Modules. Then pass that this list to Dagger to wire everything up.
Here is some pseudocode of the current implementation in Guice we want to migrate
import com.google.inject.AbstractModule;
#Feature("Wifi")
public class WifiDefaultModule extends AbstractModule {
#Override
protected void configure() {
bind(WifiManager.class).to(WifiDefaultManager.class);
bind(WifiProcessor.class).to(WifiDefaultProcessor.class);
}
}
#Feature("Wifi")
#CompatibleWithMinOS(OS > 4.4)
class Wifi44Module extends WifiDefaultModule {
#Override
protected void configure() {
bind(WifiManager.class).to(Wifi44Manager.class);
bindProcessor();
}
#Override
protected void bindProcessor() {
(WifiProcessor.class).to(Wifi44Processor.class);
}
}
#Feature("Wifi")
#CompatibleWithMinOS(OS > 4.4)
#CompatibleWithManufacturer("samsung")
class WifiSamsung44Module extends Wifi44Module {
#Override
protected void bindProcessor() {
bind(WifiProcessor.class).to(SamsungWifiProcessor.class);
}
#Feature("NFC")
public class NfcDefaultModule extends AbstractModule {
#Override
protected void configure() {
bind(NfcManager.class).to(NfcDefaultManager.class);
}
}
#Feature("NFC")
#CompatibleWithMinOS(OS > 6.0)
class Nfc60Module extends NfcDefaultModule {
#Override
protected void configure() {
bind(NfcManager.class).to(Nfc60Manager.class);
}
}
public interface WifiManager {
//bunch of methods to implement
}
public interface WifiProcessor {
//bunch of methods to implement
}
public interface NfcManager {
//bunch of methods to implement
}
public class SuperModule extends AbstractModule {
private final List<Module> chosenModules = new ArrayList<Module>();
public void addModules(List<Module> features) {
chosenModules.addAll(features);
}
#Override
protected void configure() {
for (Module feature: chosenModules) {
feature.configure(binder())
}
}
}
so at startup the app does this:
SuperModule superModule = new SuperModule();
superModule.addModules(crazyBusinessLogic());
Injector injector = Guice.createInjector(Stage.PRODUCTION, superModule);
where crazyBusinessLogic() reads the annotations of all the modules and determines a single one to use for each feature based on device properties. For example:
a Samsung device with OS = 5.0 will have crazyBusinessLogic() return the list { new WifiSamsung44Module(), new NfcDefaultModule() }
a Samsung device with OS = 7.0 will have crazyBusinessLogic() return the list { new WifiSamsung44Module(), new Nfc60Module() }
a Nexus device with OS = 7.0 will have crazyBusinessLogic() return the list { new Wifi44Module(), new Nfc60Module() }
and so on....
Is there any way to do the same with Dagger? Dagger seems to require you to pass the list of modules in the Component annotation.
I read a blog that seems to work on a small demo, but it seems clunky and the extra if statement and extra interfaces for components might cause my code to balloon.
https://blog.davidmedenjak.com/android/2017/04/28/dagger-providing-different-implementations.html
Is there any way to just use a list of modules returned from a function like we are doing in Guice? If not, what would be the closest way that would minimize rewriting the annotations and the crazyBusinessLogic() method?
Dagger generates code at compile-time, so you are not going to have as much module flexibility as you did in Guice; instead of Guice being able to reflectively discover #Provides methods and run a reflective configure() method, Dagger is going to need to know how to create every implementation it may need at runtime, and it's going to need to know that at compile time. Consequently, there's no way to pass an arbitrary array of Modules and have Dagger correctly wire your graph; it defeats the compile-time checking and performance that Dagger was written to provide.
That said, you seem to be okay with a single APK containing all possible implementations, so the only matter is selecting between them at runtime. This is very possible in Dagger, and will probably fall into one of four solutions: David's component-dependencies-based solution, Module subclasses, stateful module instances, or #BindsInstance-based redirection.
Component dependencies
As in David's blog you linked, you can define an interface with a set of bindings that you need to pass in, and then supply those bindings through an implementation of that interface passed into the builder. Though the structure of the interface makes this well-designed to pass Dagger #Component implementations into other Dagger #Component implementations, the interface may be implemented by anything.
However, I'm not sure this solution suits you well: This structure is also best for inheriting freestanding implementations, rather than in your case where your various WifiManager implementations all have dependencies that your graph needs to satisfy. You might be drawn to this type of solution if you need to support a "plugin" architecture, or if your Dagger graph is so huge that a single graph shouldn't contain all of the classes in your app, but unless you have those constraints you may find this solution verbose and restrictive.
Module subclasses
Dagger allows for non-final modules, and allows for the passing of instances into modules, so you can simulate the approach you have by passing subclasses of your modules into the Builder of your Component. Because the ability to substitute/override implementations is frequently associated with testing, this is described on the Dagger 2 Testing page under the heading "Option 1: Override bindings by subclassing modules (don’t do this!)"—it clearly describes the caveats of this approach, notably that the virtual method call will be slower than a static #Provides method, and that any overridden #Provides methods will necessarily need to take all parameters that any implementation uses.
// Your base Module
#Module public class WifiModule {
#Provides WifiManager provideWifiManager(Dep1 dep1, Dep2 dep2) {
/* abstract would be better, but abstract methods usually power
* #Binds, #BindsOptionalOf, and other declarative methods, so
* Dagger doesn't allow abstract #Provides methods. */
throw new UnsupportedOperationException();
}
}
// Your Samsung Wifi module
#Module public class SamsungWifiModule {
#Override WifiManager provideWifiManager(Dep1 dep1, Dep2 dep2) {
return new SamsungWifiManager(dep1); // Dep2 unused
}
}
// Your Huawei Wifi module
#Module public class HuaweiWifiModule {
#Override WifiManager provideWifiManager(Dep1 dep1, Dep2 dep2) {
return new HuaweiWifiManager(dep1, dep2);
}
}
// To create your Component
YourAppComponent component = YourAppComponent.builder()
.baseWifiModule(new SamsungWifiModule()) // or name it anything
// via #Component.Builder
.build();
This works, as you can supply a single Module instance and treat it as an abstract factory pattern, but by calling new unnecessarily, you're not using Dagger to its full potential. Furthermore, the need to maintain a full list of all possible dependencies may make this more trouble than it's worth, especially given that you want all dependencies to ship in the same APK. (This might be a lighter-weight alternative if you need certain kinds of plugin architecture, or you want to avoid shipping an implementation entirely based on compile-time flags or conditions.)
Module instances
The ability to supply a possibly-virtual Module was really meant more for passing module instances with constructor arguments, which you could then use for choosing between implementations.
// Your NFC module
#Module public class NfcModule {
private final boolean useNfc60;
public NfcModule(boolean useNfc60) { this.useNfc60 = useNfc60; }
#Override NfcManager provideNfcManager() {
if (useNfc60) {
return new Nfc60Manager();
}
return new NfcDefaultManager();
}
}
// To create your Component
YourAppComponent component = YourAppComponent.builder()
.nfcModule(new NfcModule(true)) // again, customize with #Component.Builder
.build();
Again, this doesn't use Dagger to its fullest potential; you can do that by manually delegating to the right Provider you want.
// Your NFC module
#Module public class NfcModule {
private final boolean useNfc60;
public NfcModule(boolean useNfc60) { this.useNfc60 = useNfc60; }
#Override NfcManager provideNfcManager(
Provider<Nfc60Manager> nfc60Provider,
Provider<NfcDefaultManager> nfcDefaultProvider) {
if (useNfc60) {
return nfc60Provider.get();
}
return nfcDefaultProvider.get();
}
}
Better! Now you don't create any instances unless you need them, and Nfc60Manager and NfcDefaultManager can take arbitrary parameters that Dagger supplies. This leads to the fourth solution:
Inject the configuration
// Your NFC module
#Module public abstract class NfcModule {
#Provides static NfcManager provideNfcManager(
YourConfiguration yourConfiguration,
Provider<Nfc60Manager> nfc60Provider,
Provider<NfcDefaultManager> nfcDefaultProvider) {
if (yourConfiguration.useNfc60()) {
return nfc60Provider.get();
}
return nfcDefaultProvider.get();
}
}
// To create your Component
YourAppComponent component = YourAppComponent.builder()
// Use #Component.Builder and #BindsInstance to make this easy
.yourConfiguration(getConfigFromBusinessLogic())
.build();
This way you can encapsulate your business logic in your own configuration object, let Dagger provide your required methods, and go back to abstract modules with static #Provides for the best performance. Furthermore, you don't need to use Dagger #Module instances for your API, which hides implementation details and makes it easier to move away from Dagger later if your needs change. For your case, I recommend this solution; it'll take some restructuring, but I think you'll wind up with a clearer structure.
Side note about Guice Module#configure(Binder)
It's not idiomatic to call feature.configure(binder()); please use install(feature); instead. This allows Guice to better describe where errors occur in your code, discover #Provides methods in your Modules, and to de-duplicate your module instances in case a module is installed more than once.
Is there any way to just use a list of modules returned from a
function like we are doing in Guice? If not, what would be the closest
way that would minimize rewriting the annotations and the
crazyBusinessLogic() method?
Not sure this is the answer you're looking for, but just in case you do have other options and for other community members I will describe completely different approach.
I would say that the way you used Guice until now is an abuse of DI framework, and you will be much better off leveraging this opportunity to remove this abuse instead of implementing it in Dagger.
Let me explain.
The main goal of dependency injection architectural pattern is to have construction logic segregated from functional logic.
What you basically want to achieve is standard polymorphism - provide different implementations based on a set of parameters.
If you use Modules and Components for that purpose, you will end up structuring your DI code according to business rules governing the need for these polymorphic implementations.
Not only will this approach requires much more boilerplate, but it also prevents emergence of cohesive Modules that have meaningful structure and provide insights into application's design and architecture.
In addition, I doubt you will be able to unit test these business rules "encoded" inside dependency injection logic.
There are two approaches which are much better IMHO.
First approach is still not very clean, but, at least, it doesn't compromise the large scale structure of dependency injection code:
#Provides
WifiManager wifiManager(DeviceInfoProvider deviceInfoProvider) {
if (deviceInfoProvider.isPostKitKat() ) {
if (deviceInfoProvider.isSamsung()) {
return new WifiMinagerSamsungPostKitKat();
} else {
return new WifiMinagerPostKitKat();
}
} else {
return new WifiMinagerPreKitKat();
}
}
The logic that chooses between implementation still resides in DI code, but, at least, it did not make it into the large scale structure of that part.
But the best solution in this case is to make a proper object oriented design, instead of abusing DI framework.
I'm pretty sure that the source code of all these classes is very similar. They might even inherit from one another while overriding just one single method.
In this case, the right approach is not duplication/inheritance, but composition using Strategy design pattern.
You would extract the "strategy" part into a standalone hierarchy of classes, and define a factory class that constructs them based on system's parameters. Then, you could do it like this:
#Provides
WiFiStrategyFactory wiFiStrategyFactory(DeviceInfoProvider deviceInfoProvider) {
return new WiFiStrategyFactory(deviceInfoProvider);
}
#Provides
WifiManager wifiManager(WiFiStrategyFactory wiFiStrategyFactory) {
return new WifiMinager(WiFiStrategyFactory.newWiFiStrategy());
}
Now construction logic is simple and clear. The differentiation between strategies encapsulated inside WiFiStrategyFactory and can be unit tested.
The best part of this proper approach is that when a new strategy will need to be implemented (because we all know that Android fragmentation is unpredictable), you won't need to implement new Modules and Components, or make any changes to DI structure. This new requirement will be handled by just providing yet another implementation of the strategy and adding the instantiation logic to the factory.
All that while being kept safe with unit tests.
In my Application class, I have my singleton Dagger Component as a static object and reach it via its static getter method.
public class MyApp extends Application {
private static UtilsComponent utilsComponent;
#Override
public void onCreate() {
......
}
public static UtilsComponent getUtilsComponent(){
if(utilsComponent == null){
utilsComponent = DaggerUtilsComponent.builder()
.formattersModule(new FormattersModule())
.build();
}
return utilsComponent;
}
}
What I want to know is that is this the right way to do this? Can it cause problems? If so, what are those?
It's okayish. But why would you put it in the Application class? Put it in standard singleton class called for example Injector. Still you might want to initialize that singleton in Application which is fine.
It is ok, but you will not be able to use inject Context- dependent objects in that way. For component, requiring Context, use non - static accessor in Application class.
Speaking more widely, there will be as many components as your want, but if if component provides #Singleton - annotated functionality, lifecycle of component should not be longer that one of feature using it.
I just tested out Dagger 2 and I am having some strange behaviour regarding the singleton annotation. I created some test code to show my problem.
My Module:
#Module
public class App {
#Provides
#Singleton
ThingA provideThingA(){
return new ConcreteThingA();
}
}
Interface of the thing I want in singleton:
public interface ThingA {
void showMyId();
}
Implementation:
public class ConcreteThingA implements ThingA {
#Override
public void showMyId() {
System.out.println(this);
}
}
Code that executes Dagger:
public void doStuff() {
ThingA thingA=DaggerThingAComponent.create().provideThingA();
ThingA thingB=DaggerThingAComponent.create().provideThingA();
System.out.println("Hello");
}
And here is a screenshot showing that I do not get the same instance when I ask for it twice. Have I missed something fundamental? ThingA is just a silly name and in my actual application I would like to have this singleton behaviour on my services.
The trick is that Dagger enforces scope/lifecycle through components, and you've created two separate components here:
ThingA thingA = DaggerThingAComponent.create().provideThingA();
ThingA thingB = DaggerThingAComponent.create().provideThingA();
Each time you create the new top-level #Singleton-annotated Component, Dagger creates a brand new object graph with a brand new container for each #Singleton object. You should have this instead:
ThingAComponent component = DaggerThingAComponent.create();
ThingA thingA = component.provideThingA();
ThingA thingB = component.provideThingA(); // thingA == thingB
Of course, anything further accessed through the dependency graph all comes from the same component, so this will preserve the singleton behavior you're looking for.
In most cases, you should not need to pass around the Component: The Component should be used for top-level components, and anything accessible through the injector should #Inject its dependencies (which means it shouldn't need a reference to the component itself). This might appear problematic during the migration to DI or Dagger, but creating multiple #Singleton components is not the way around it. Instead, try one of the following:
If you need multiple instances of something, you can always inject Provider<T> instead of T whether or not you've created a #Provides method. For that matter, you can inject a Lazy<T> if you only need zero or one copies of a particular dependency, particularly if the creation of that object is particularly heavy.
You can #Inject the component itself if you need it deep within the object graph, though it's always preferable to #Inject Provider<T> tProvider instead of #Inject YourComponent just to call YourComponent.getT.
In some cases, including Android, it may make sense to save the component to a globally-accessible field, either as an instance field in your Application or as a static field somewhere else. This is specifically because Android creates objects on its own, reflectively, rather than getting injected instances from the graph. For all other cases, inject your dependencies to avoid needing to pass around the component.
See also: Bindings in the graph from the Dagger 2 Users Guide
Lot's of times, classes need to be instantiated (constructed), and then "wired" (configured) before they can be used. For instance:
// Construction.
EventBus bus = new EventBus();
FizzEventHandler fizzHandler = new FizzHandler();
BuzzEventHandler buzzHandler = new BuzzHandler();
// Wiring.
bus.register(fizzHandler);
bus.register(buzzHandler);
In Guice, we accomplish the first part (construction; injection) with a Binder:
public class MyModule extends AbstractModule {
#Override
public void configure() {
bind(EventBus.class).to(SimpleEventBus.class);
bind(FizzEventHandler.class).to(DefaultFizzEventHandler.class);
bind(BuzzEventHandler.class).to(DefaultBuzzEventHandler.class);
}
}
But where does the wiring take place? When my Guice-based app starts up, we engage the DI "bootstrapping" process:
public class MyApp {
private EventBus bus;
private FizzEventHandler fizzHandler;
// ...etc.
public static void main(String[] args) {
MyApp app = new MyApp();
app.run();
}
public MyApp() {
// Bootstrap DI.
MyModule myModule = new MyModule();
Injector injector = Guice.createInjector(myModule);
bus = injector.inject(EventBus.class);
fizzHandler = injector.inject(FizzEventHandler.class);
// ...etc.
// Wire
bus.register(fizzHandler);
}
}
This works OK for the top-level (root) DI classes. But as we get further "down" the dependency tree, and get into all the other objects used by the application, putting the wiring logic in constructors like this is ugly and (I believe) is a discouraged practice.
So I ask: where doe battle-weary Guice veterans place their wiring/config code?
I work on a reasonably big system (~3000 classes) which uses Guice. I would say that our approach is to do everything with constructors. There aren't distinct "construction" and "wiring" activities as you describe, there's only construction.
In your example, the event handlers would be constructor parameters to the bus, which would register them in its constructor.
If you want to have fairly flexible injection of all the components of a given type (here, you would want to inject all event listeners into the bus), you could use multibindings. However, i don't think we actually use this in our codebase; we just write out manual lists of everything that needs injecting, which turns out not to be all that arduous in practice.
I generally use multiple modules, separated out by logical function. So one module might have authentication in it, another has data repositories, another the messaging system that I'm using, etc. This allows you to have different modules for mocking, caching Vs. non-caching, or just different implementations of the same service, and to switch out chunks of dependencies quickly and easily.
To make things even more flexible you could have a configuration file which declares the modules that should be used when the injector starts up.
When I have some logic to be done right after I instantiate my object I usually do it in methods annotated with #Provides. Your example might looks like this :
public class MyModule extends AbstractModule {
#Override
protected void configure() {
bind(FizzEventHandler.class).to(DefaultFizzEventHandler.class);
bind(BuzzEventHandler.class).to(DefaultBuzzEventHandler.class);
}
#Provides
public EventBus getEventBus(SimpleEventBuss simpleBus/* this here is going to be injected as it is a class not an interface and Guice is clever and it know how to do it ;) */
, FizzEventHandler fizz, BuzzEventHandler buzz) {
simpleBus.register(fizz);
simpleBus.register(buzz);
return simpleBus;
}
}
I have a use case where it appears that referencing a Guice injector from multiple locations is the only solution—though this is generally discouraged.
My application is built on top of Talend, an open source ETL platform. Most of my actual application is in Java classes that are called by Talend components. These components include Java snippets that I write and that, in turn, instantiate/invoke my classes.
Now I intend to use Guice throughout my Java classes but there is absolutely no way for me to inject dependencies into the Talend components (so that they would be available to the Java snippets). Instead, I need to actually create these dependencies. I’d like to at least have Guice control the instantiation, which means that instead of using new, it appears that the only way I can instantiate my classes (the ones with #Inject constructors) is to call injector.getInstance. This, in turn, implies that I need to keep the injector around, presumably using an old-fashioned factory that creates it in the first place and makes it available as a singleton.
I just can’t see any other way to handle this but perhaps I’m missing something.
Consider static injection. This will still hide persistent references to your injector across your app, but it will save you from having to pepper your code with injector.getInstance(...) calls. In any case you can inject Injector if you really need to.
class TalendDependencyModule extends AbstractModule {
#Override public void configure() {
requestStaticInjection(ExtractorDependencies.class);
requestStaticInjection(ProcessorDependencies.class);
}
}
public class ExtractorDependencies {
#Inject private static Provider<ParserService> parserServiceProvider;
#Inject private static Provider<SomethingElse> somethingElseProvider;
private ExtractorDependencies() { }
static ParserService getParserService() {
return parserServiceProvider.get();
}
/* ... */
}
I don't know how many Talend objects you have but you might want to consider using providers. For instance suppose you have your own class that you want Guice to manage creation of:
public interface INotTalendControlled {}
public class NotTalendControlled implements INotTalendControlled {}
This will be added to a Talend object whose dependencies cannot be injected via Guice (although I assume there is some manual process for doing so either constructor or setter):
public class TalendControlled {
private INotTalendControlled notTalendControlled;
private TalendControlled(INotTalendControlled notTalendControlled) {
this.notTalendControlled = notTalendControlled;
}
public INotTalendControlled getValue() {
return notTalendControlled;
}
}
If you want Guice to manage these lifecycles and the lifecycle of Talend controlled objects you can use a provider like so:
public static class TestModule extends AbstractModule {
#Override
protected void configure() {
bind(INotTalendControlled.class).to(NotTalendControlled.class);
}
#Provides
public TalendControlled provideInjectsToTalendObject(INotTalendControlled notTalendControlled) {
return new TalendControlled(notTalendControlled);
}
}
The #Provides method will hide of the use of new for all objects as you can now directly inject TalendControlled objects (#Inject TalenControlled talendControlled) and an explicit injector is not needed to construct their dependencies.