does dagger recognize super class dependencies - dependency-injection

My setup is like this
interface ServiceProvider {...}
#Singleton
class ServiceProviderImpl implements ServiceProvider {...}
class ServiceConsumer {
#Inject
ServiceConsumer(ServiceProvider prov) {...}
}
Unfortunately, this doesn't work as it claims there are no providers for ServiceProvider, even though there is one for subclass ServiceProviderImpl.
I get
error: [Dagger/MissingBinding] c.b.d.s.ServiceProvider cannot be provided without an #Provides-annotated method.
I can fix this by adding the following to the module
#Provides
#Singleton
ServiceProvider serviceProvider(ServiceProviderImpl impl) {return impl;}
Is this by design, or am I doing something wrong?

This is by design. Dagger makes no assumptions about what implementation of an interface to use without you specifying it somewhere.
For binding an implementation for an interface you should use #Binds, though, which is an optimized version of #Provides for implementation -> interface bindings.
#Binds
#Singleton
ServiceProvider serviceProvider(ServiceProviderImpl impl);

Related

Dart implements/extends for abstract class

For abstract classes is there difference between implements and extends? Which one should I use? In Java for interfaces you would use implements, but I see dart doesn't have interfaces and both implements/extends work. If I want to declare abstract class for my api methods, should I use implements or extends?
void main() {
User user = new User();
user.printName();
}
abstract class Profile {
String printName();
}
class User extends Profile {
#override
String printName() {
print("I work!!");
return "Test";
}
}
All classes in Dart can be used as interfaces. A class being abstract means you cannot make an instance of the class since some of its members might not be implemented.
extends means you take whatever a class already have of code and you are then building a class on top of this. So if you don't override a method, you get the method from the class you extends from. You can only extend from one class.
implements means you want to just take the interface of class but come with your own implementation of all members. So your class ends up being compatible with another class but does not come with any of the other class's implementation. You can implement multiple classes.
A third options, which you did not mention, is mixin which allow us to take the implementation of multiple mixin defined classes and put them into our own class. You can read more about them here: https://dart.dev/guides/language/language-tour#adding-features-to-a-class-mixins

What happens if you pass an Injector as argument in a #Provides method

I have seen several usage in a project I am working as the following (I am posting the essence of the code so it is easier to read):
public static void main(Strings[] args) {
Injector i = Guice.createInjector(new MyModule());
i.getInstance(Foo.class);
}
class Foo {}
class MyModule extends AbstractModule {
#Provides
public Foo getFoo(Injector injector) {
return new Foo();
}
}
When I tried to print the injector.toString() in the module I think Guice somehow bound the Injector to the instance i itself.
Like for example
public static void main(Strings[] args) {
Injector i = Guice.createInjector(new MyModule());
Injector j = i.getInstance(Injector.class);
if (i == j) {
// true
}
}
....
So in this case can someone please shed some light on how Guice obtains the instance of Injector in the getFoo(injector) method? Thanks!
Injector is injectable in your graph, and Guice will supply arguments to #Provides methods. However, you should only ever need to inject your Injector in very rare cases, and there is no need to request an Injector if you don't use it.
#Provides
public Foo getFoo(Dep1 dep1, Dep2 dep2) {
return new Foo(dep1, dep2);
}
This assumes Guice can create instances of Dep1 and Dep2 (via constructors, bindings, or #Provides methods), and is roughly equivalent to if you had annotated a constructor in Foo. Guice will inject instances of Dep1 and Dep2 when calling the Foo constructor, and Guice will provide the instances when calling your #Provides Foo getFoo method above.
#Inject public Foo(Dep1 dep1, Dep2 dep2) { /* ... */ }
As in the documentation for the Injector class that you linked (latest docs available here):
Contains several default bindings:
This Injector instance itself
A Provider<T> for each binding of type T
The Logger for the class being injected
The Stage in which the Injector was created
Consequently, you may put Dep1, Dep2, Provider, Provider, Injector, or Provider<Injector> into your #Provides method arguments or #Inject constructor arguments (or #Inject fields, etc). Internally, Injector support happens in InjectorShell.java as a special case, because parent and child Injectors will return different instances of Injector as an exception to Guice's rules about parents and children with the same bindings.
Why would you want to inject an Injector? For the sake of reading and testing, it is usually better to inject the dependency you need (e.g. Dep1) or its provider (e.g. Provider<Dep1>). You would only need to inject the Injector if you need to pass it into some other object, like a legacy Service Locator that you've adapted to use your Guice Injector, or if you need to use the Injector reflectively via Guice's SPI or to get an instance based on a Class object. These are rare, and not likely to be necessary in most of your classes or #Provides methods.
/** Exceptions, generics, and casting omitted for readability. */
#Provides SomeInterface getSomeInterface(
MyAppPreferences preferences,
Injector injector) {
Class<?> clazz = Class.forName(preferences.getSomeInterfaceImplName());
return injector.getInstance(clazz);
}
See also: Accessing Guice injector in its Module?

Guice: Injecting an object from an installed module to a dependent installed module

I'm quite new to new Guice, but I've been reasonably successful with it until this point.
I have a 'main' Guice module (ServerModule) as follows which installs several other modules:
public class ServerModule extends AbstractModule {
#Override
protected void configure() {
install(new DbModule());
install(new ModuleA());
install(new ModuleB());
}
}
The first installed module (DbModule) is as follows:
public class DbModule extends AbstractModule {
#Override
protected void configure() {
bind(DbService.class).to(DbServiceImpl.class).asEagerSingleton();
}
}
The issue I am having is that the other two modules depend on the DbService instance created by the DbModule. I.E. I need to inject the DbService object in to the other two installed modules (ModuleA and ModuleB).
As ModuleA and ModuleB are not created by the injector (I am constructing them as shown above), I am unable to inject the DbService instance created into these modules or even pass them in to the constructors. I.E:
install(new DbModule());
install(new ModuleA(dbService));
install(new ModuleB(dbService)));
I have already experimented with using a provider #provider to provide an instance of DbService, but as I am constructing the modules manually as shown above, it won't work.
If I could get the injector to create ModuleA and ModuleB, I guess I would then be able to inject the DbService instance in to them, but I can't figure out how to do that.
Does anyone have any ideas of how I can best accomplish this?
EDIT: I forgot to mention that the reason #provider seems to be of no use is because I need to use the DbService in ModuleA itself, not in one of it's bindings:
public class ModuleA extends AbstractModule {
#Inject
private DbService dbService;
#Override
protected void configure() {
if( dbService.getX() )
bind(Y.class);
}
}
You cannot and should not do this because Guice modules are not supposed to be used this way.
Basically, Guice encourages to separate configuration from actual object creation. You simply cannot inject into modules unless you create an injector, use it to create new modules, and then create another injector with these modules.
And this in fact is very good. Your modules should not usually have complex logic inside them, it is just a configuration, after all. You should refactor your program, for example, to use #Provides-methods or full-fledged Providers. Then you will have much more cleaner dependency configuration logic.
You can't do that.
The Module.configure() method is called when creating an Injector, and injections could only happen after the Injector is ready to use.

Dagger field injection and entry points

I am trying dagger in one of my projects and i am experiencing this situation:
"Field injection only works if I declare the class as an entry point in the module definition."
Is this the correct behaviour?
The below dependencies are not injected to Messenger class if Messenger.class is not declared as an entry point. Constructor injector works fine but I don't want to declare a multi parameter constructor.
public class Messenger implements NetworkInterfaceListener {
#Inject public NetworkInterface networkInterface;
#Inject public MessageFactoryInterface messageFactory;
#Inject public Bus bus;
#Inject public Logger log;
...
...
}
You have only two alternatives: either to declare injectable constructor with all params to be injected or enlist class into entryPoints (now called injects) of your dagger module and call mGraph.inject(this) in default constructor (or whenever you need to actually "inject" maybe even outside the class).

Unexpected key in dagger compilation

I get the following error from dagger:
[ERROR] error on execute: java.lang.IllegalArgumentException: Unexpected key: ca.nanometrics.apollo.instrument.configuration.ResourceOwnerController<>
I believe this happens because I have a class with no injectable dependencies - it has an empty public constructor (with #Inject), with nothing to inject in members either. I did this to not have to declare the #Provides for it. Note that the class with the #Inject is a subclass of the class listed in the error message above:
public class ResourceOwnerControllerHelios extends ResourceOwnerController<ResourceOwnerFactoryHelios>
{
#Inject
public ResourceOwnerControllerHelios()
{
// do nothing
}
Is this a bug in dagger, or is there something I am missing?
If I remove the #Inject and still don't add the #Provides to the module, it of course doesn't work at all, since dagger needs #Inject or #Provides on all dependencies.
Oi - this looks like its' bumping into a mishandling of generics. :/ Maybe file an issue on github. What you're doing should work - that is, adding #Inject to a no-args public constructor. I believe Dagger is trying to climb the inheritance hierarchy and not handling the generics in the parent. We should be handling this case.

Resources