Getting rid of Dagger 2 warning "Generating a MembersInjector" - java

Given the following classes
abstract class AbstractClass {
#Inject SomeDependency someDependency;
}
class SomeClass extends AbstractClass {
#Inject AnotherDependency anotherDepenency;
public void onCreate() {
component = // Get component instance somehow
component.inject(this);
}
}
in Dagger 2 when injecting dependencies into a class which extends from an abstract base class which also contains dependencies, Dagger shows a warning of the kind Generating a MembersInjector for AbstractClass. Prefer to run the dagger processor over that class instead. during compilation.
However if I override/implement onCreate() in AbstractClass and call the dependency injection there, too, the dependency someDependency will be injected twice which might lead to unexpected behaviour. Once in onCreate() of AbstractClass and once in onCreate() of SomeClass.
What is the best solution to get rid of this warning while preventing duplicate injection of dependencies?

As of Dagger 2.9 these warnings are off by default.

Solution could be: define onCreate() in Abstract class only

Related

Guice injection in a child class of a AbstractModule class

This is regarding to the Play framework 2.5.x
I have few Guice modules which extended by the AbstractModule and they are added as bindings to the GuiceApplicationBuilder method like below.
#Override
public GuiceApplicationBuilder builder(ApplicationLoader.Context context) {
return initialBuilder
.in(context.environment())
.bindings(new LoggerModule())
.bindings(new BaseConnectionModule(configuration))
.bindings(new CacheModule(configuration))
.bindings(new DaoModule())
....
One of my module (say CacheModule) declared private variables in that which are also Guice injected to be used in that class(inside Guice #Provides methods). The bindings for those variable are done in one of a GuiceModule (say BaseConnectionModule) which bound prior to the current module as mentioned in above code.
My question is, when the application get started, such variables declared as private in the CacheModule are not get instantiated.
Can someone please answer to this?

Spring/DI: Constructor injection in child class

I've got a parent class with a constructor injected dependency:
class ParentClass {
private final MyService service;
#Autowired
ParentClass(MyService service) {
this.service=service;
}
// ...
}
If I inherit from this class, do I always need to redefine a constructor calling the parent constructor?
class ChildClass extends ParentClass {
// Do I really need this?
#Autowired
ChildClass(MyService service) {
super(service);
}
// ...
}
Using setter injection, I seem to be able to keep the dependency in the parent class and do not need to rewire it in the child, which sounds good to me if the child class does not touch the functionality linked to the dependency:
class ParentClass {
private MyService service;
#Autowired
void setMyService(MyService service) {
this.service=service;
}
// ...
}
class ChildClass extends ParentClass {
// ...
}
It seems that if I want to avoid repeating the autowiring code and handling the dependency in the child, I can only do this using setter or field injection.
Is there a cleaner pattern to do this dependency injection or is this a case where field/setter injection has to be used, even though constructor injection is recommended?
Thanks!
It's not a Spring issue, it's Java. Try removing child class constructor, and see what happens for yourself - your code shouldn't compile. See this answer, it was described before.
Answering your question on dependency injection, yes, #Autowired works for setter in the parent class, but as long as you don't override it in the subclass (give it a try). The reason is that Spring deals with objects, not classes, so when a subclass is instantiated Spring is not checking annotations on overridden methods in the parent class, unless annotation is marked as #Inherited (#Autowired is not).
So, you would either have to use #Autowired for each subclass (which I don't see as a big problem, actually), switch to setter injection, replace subclassing with delegation, or make parent class abstract and use constructor injection only in subclasses.

Migrating a Guice-based project to Dagger

I have a Guice based project using vanilla Guice;
no Assisted-Inject, no AOP, no extra plugin extending Guice, etc.
To run it more easily on Android, Dagger seems like a better solution.
Every class has a dependency and a constructor with #Inject annotation.
No field or method injection is used.
The modules are quite simple (making Guice an overkill) and mostly contain bindings like the following:
class SomethingModule extends AbstractModule {
protected void configure() {
Bind(Handler.class)
.annotatedWith(Names.named("something"))
.to(SomeImplementation.class);
}
}
}
And later used like the following:
Injector inj = Guice.createInjector(new SomethingModule());
... = inj.getInstance(SampleInterface.class);
// and rest of the code.
Unfortunately,
I can not get my head around Daggers terminology.
Can you guide me with a direct translation / transformation of a Guice module to a Dagger module?
Dagger has:
Dagger's Components.
Dagger's Modules.
#Provides
#Inject
Guice has:
#Inject
#Named (or any custom annotation, if implemented correctly).
Our modules extending AbstractModule.
#Provides in the modules.
Guice Injector created from modules.
How do these relate?
Update: In addition to the nice answer by EpicPandaForce, these slides can help too.
Bind(Handler.class)
.annotatedWith(Names.named("something"))
.to(SomeImplementation.class);
Would translate to
#Module
public class SomethingModule {
#Provides
#Named("something")
//scope if needed
public Handler handler() {
return new SomeImplementation();
}
}
Which would be bound to an "Injector" (component):
#Component(modules={SomethingModule.class})
//scope if needed
public interface SomethingComponent {
#Named("something")
Handler handler();
void inject(ThatThingy thatThingy);
}
Which is an "injector" that you have to create with the APT-generated builder:
SomethingComponent somethingComponent = DaggerSomethingComponent.builder()
.somethingModule(new SomethingModule()) //can be omitted, has no params
.build();
somethingComponent.inject(thatThingy);
Where that thingy has
public class ThatThingy {
#Inject
#Named("something")
Handler handler;
}
Components typically exist per scope, so for example #ApplicationScope has one "injector" (component). Scoping can be achieved with subcomponents and component dependencies.
Important fact, a component has provision methods (which are the dependencies that are inherited to subscoped components if you use component dependencies), and void inject(X x); formatted methods. This is required for field injection per concrete type. A base class for example can only inject itself, and not its subclasses. You can however write a method called protected abstract void injectThis() which would call the .inject(this) on the subclass as well.
As I haven't really used Guice, I'm not sure if I missed out on anything. I think I forgot constructor injection, which is an issue because while Dagger does support it, it cannot be reconfigured. For reconfiguration, you have to use modules, and do the injection in the constructors yourself.
#Module(includes={ThoseModule.class, TheseModule.class})
public abstract class SomethingModule {
#Binds
abstract Whatever whatever(WhateverImpl impl);
}
#Singleton
public class WhateverImpl implements Whatever {
Those those;
These these;
#Inject
public Whatever(Those those, These these) {
this.those = those;
this.these = these;
}
}
#Component(modules={SomethingModule.class})
#Singleton
public interface SomethingComponent {
These these();
Those those();
Whatever whatever();
}

Dagger2 custom #Qualifier usage

Suppose I'm building a car and I have several Brake beans with different implementations
class Car {
#Inject
Car(#BrakeType(value="abs")Brake frontBrake, #BrakeType(value="nonabs")Brake rearBrake) { }
}
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
public #interface BrakeType {
String value();
}
interface Brake {}
#BrakeType(value="abs")
class AbsBrakeImpl implements Brake {
#Inject AbsBrakeImpl() {}
}
#BrakeType(value="nonabs")
class BrakeImpl implements Brake {
#Inject BrakeImpl() {}
}
why does my CarModule have to define #Provides for the specific Brake types? Shouldn't the custom annotation type #BrakeType be enough to determine which impl to inject? Or would that require using reflection, which dagger2 does not use?
#Module
public class CarModule {
#Provides #BrakeType("abs")
public Brake absBrake() {
return new AbsBrakeImpl();
}
#Provides #BrakeType("nonabs")
public Brake nonabsBrake() {
return new BrakeImpl();
}
}
Dagger doesn't look at qualifier annotations on classes, only on #Provides or #Binds methods. So the #BrakeType(value="abs") annotations on your classes don't have any effect.
A more canonical way of writing your code is:
class AbsBrakeImpl implements Brake {
#Inject AbsBrakeImpl() {}
}
class BrakeImpl implements Brake {
#Inject BrakeImpl() {}
}
#Module
abstract class CarModule {
#Binds #BrakeType("abs")
abstract Brake absBrake(AbsBrakeImpl impl);
#Binds #BrakeType("nonabs")
abstract Brake nonabsBrake(BrakeImpl impl);
}
Note that since you have #Inject on the constructors of your implementations, you can simply use Dagger's #Bind to bind the implementations directly to the appropriately qualified interface.
Reflection is probably not a big issue here because it would happen at compile time.
I did not look through the source code, but dagger is but an annotation processor—it registers to be called whenever a set of given annotations is used. While the qualifier alone would probably be enough to find out what you intended, I can think of the following reasons why this could not be the best solution.
javax.inject.Qualifier is part of a bigger API, and might also be used by other libraries in different context. So you might not want dagger to generate code for a method, just because it is annotated with a qualifier.
Another reason could be that since there is the possibility to create custom qualifiers, dagger would have to check every annotation on every method in every module and then in turn determine whether that annotation itself is annotated with #Qualifier to see if the method is of some interest to it. This is rather an unnecessary overhead.
There might be more reasons, but those 2 listed here seem enough to just make users of dagger use some sort of contract: #Provides.
Annotations don't affect the performance of the code, and having an addtional annotation won't do any harm, so there is more to gain than to lose by handling it the way they do.
For the record, you can use your own qualifier annotations (as BrakeType), or just use #Named from Dagger.
Using this last one, your code will look something like:
#Inject #Named("abs") Brake frontBrake;
#Inject #Named("nonabs") Brake rearBrake;
And on your module:
#Provides #Named("abs") static Brake provideAbsBrake() {
return new AbsBrakeImpl();
}
#Provides #Named("nonabs") static Brake provideNonAbsBrake() {
return new BrakeImpl();
}
Remember to use Dagger name conventions (like provide prefix) to get most of it. And on your modules try to use all #Provides methods static, doing so the resultant implementation does not need to instantiate it.
In short, Provides and Qualifiers work together so you need both.
Source: Dagger users guide.
#Inject constructor means provide a type that class itself, in your case, which mean you provide the AbsBrakeImpl type and BrakeImpl type, so when you try to inject with Brake, dagger can not found the provider.
Qualifier in #Inject constructor is not work, because class type is unique, we don't need to add a qualifier to.
So, in your case, or you have to use CarModule to tell Dagger explicitly, or change your constructor with
class Car {
#Inject
Car(AbsBrakeImpl frontBrake, BrakeImpl rearBrake) { }
}

How to use a mock Object with Assisted Inject instead of real implementation class

I have the following abstract class :
public abstract class MyClass
Then I have the two following abstract classes which extend this one :
public abstract class AClass extends MyClass
and
public abstract class BClass extends MyClass
I have to use dependency injection for the instantiation of my objects. The constructor of the classes which extend the classes AClass and BClass receive a String as an argument and for this reason I use the AssistedInject extension from Google Guice.
In my normal BinderModule I have the following code :
public class BinderModule implements Module{
#Override
public void configure(Binder binder) {
binder.install(
new FactoryModuleBuilder().
implement(AClass.class, AClassImpl.class).
build(AClassFactory.class));
binder.install(
new FactoryModuleBuilder().
implement(BClass.class, BClassImpl.class).
build(BClassFactory.class));
}
}
I also want to use a Module for testing purposes which will have mocked Objects for substituting AClassImpl and BClassImpl.
When I have used injection so far I did something like this :
InterfaceA myMockObj = EasyMock.createMock(InterfaceAImpl.class);
binder.bind(InterfaceA.class).toInstance(myMockObj);
The problem is that now the implement method receives only Class arguments and I cannot connect the mocked Objects to the Abstract classes.
Any ideas on how I can overcome this ?
In general, unit tests are simpler if you don't use Guice at all. But if you really want to, you could mock the factory interface like this:
BClass myMockObj = EasyMock.createMock(BClass.class);
BClassFactory mockFactory = EasyMock.createMock(BClassFactory.class);
EasyMock.expect(mockFactory.create(arguments)).andStubReturn(myMockObj);
bind(BClassFactory.class).toInstance(mockFactory);
instead of using assisted injection which isn't going to play nice with mocks.

Categories

Resources