Dependency Injection - Dagger2 - Generics - java

I am having problems injecting a generic type interface. Not sure how to do this or google it since I don't know the exact terms to search for. Sorry if i'm completely wrong just getting started with dagger.
Basically I have a use case class
public class LoadConversations<C extends IConversation>
extends UseCase<List<C>, LoadConversations.Type> {
private final IConversationRepository<C> messageRepository;
#Inject LoadConversations(#NonNull IConversationRepository<C> messageRepository) {
this.messageRepository = messageRepository;
}
....
public enum Type {
ALL, NEWER, OLDER
}
}
With IConversationRepository being an interface.
public interface IConversationRepository<C extends IConversation> {
Observable<List<C>> conversations(LoadConversations.Type params);
}
IConversation being a blank interface and ConversationModule where i provide the IConversationRepository.
Im having problems injecting with the following code. Am i missing something or doing something completey wrong. Thanks in advance.
Trying to provide as follows:
#Provides IConversationRepository<Conversation> provideConversationRepository(
ConversationRepository conversationRepository) {
return conversationRepository;
}
And I'm trying to inject this to my presenter as
private final LoadConversations<Conversation> loadConversations;
#Inject public ConversationListPresenter(LoadConversations<Conversation> loadConversations) {
this.loadConversations = loadConversations;
}
Implementation of ConversationRepository
public class ConversationRepository implements IConversationRepository<Conversation> {
#Override public Observable<List<Conversation>> conversations(LoadConversations.Type params) {
....
}
}
Error Log:
Error:(15, 10) error: com.rbttalk.android.data.repository.ConversationRepository cannot be provided without an #Inject constructor or from an #Provides-annotated method.
com.rbttalk.android.data.repository.ConversationRepository is injected at
com.rbttalk.android.di.module.sub_modules.ConversationModule.provideConversationRepository(conversationRepository)
com.rbttalk.android.domain.repository.IConversationRepository<com.rbttalk.android.domain.models.Conversation> is injected at
com.rbttalk.android.domain.usecase.conversation.LoadConversations.<init>(arg0, …)
com.rbttalk.android.domain.usecase.conversation.LoadConversations<com.rbttalk.android.domain.models.Conversation> is injected at
com.rbttalk.android.ui.main.conversation.ConversationListPresenter.<init>(loadConversations)
com.rbttalk.android.ui.main.conversation.ConversationListPresenter is injected at
com.rbttalk.android.ui.main.conversation.ConversationListFragment.userListPresenter
com.rbttalk.android.ui.main.conversation.ConversationListFragment is injected at
com.rbttalk.android.di.component.ConversationComponent.inject(conversationListFragment)

You're very close! The error message says it all:
com.rbttalk.android.data.repository.ConversationRepository cannot be provided without an #Inject constructor or from an #Provides-annotated method.
Note that this is not IConversationRepository; you've provided a binding for that with your #Provides method (which you can eventually consider converting to a #Binds method). However, that #Provides method has a parameter, ConversationRepository, which effectively asks Dagger to create an instance of that concrete ConversationRepository type for you. You've made that binding correctly, but now Dagger needs to instantiate ConversationRepository for you, and it simply doesn't know how.
You'll need to create an #Inject-annotated constructor for ConversationRepository using the annotation type javax.inject.Inject, even if it just looks like this:
#Inject ConversationRepository() {}
This allows Dagger to know that yes, it is safe to call that constructor. (This differs from Guice, which was willing to call a public parameterless constructor including the default constructor provided by Java.) Though you are welcome to accept injector-provided parameters in that annotated constructor (which might be nice if your repository has dependencies, because then you can keep the fields final), you may also choose to simply annotate some fields with #Inject and let the injector populate those after creation.

Related

Spring constructor injection and super call verbosity

I started to use constructor injection in my projects since Spring declared field injection to be deprecated. Actually, the code feels prettier and more strict, I'm ok with that.
But I encountered a pattern which seems a bit...weird and verbose to me:
I have an abstract service bean class (with #Service annotation), which has, say 2 dependencies, injected directly in the constructor:
#Autowired
public AbstractService(DependencyA depA, DependencyB depB) {
this.depA = depA;
this.depB = depB;
}
Then I have multiple services bean classes (still with #Serviceannotation) extending the abstract one.
And I don't know if there is another way but this is where I find a bit verbose and repetitive having to inject the dependencies for the parent, in each sub-class constructor:
#Service
public class ServiceA extends AbstractService {
private final DepC depC;
#Autowired
public ServiceA(DepA depA, DepB depB, DepC depC) {
super(depA, depB);
this.depC = depC;
}
}
I just wanted to know if this is the right way, and what you think about this ?
The #Autowired on AbstractService doesn't do anything. Change it to:
#Service
public class ServiceA extends AbstractService {
private final DepC depC;
#Autowired
public ServiceA(DepA depA, DepB depB, DepC depC) {
super(depA, depB);
this.depC = depC;
}
}
...
public AbstractService(DependencyA depA, DependencyB depB) {
this.depA = depA;
this.depB = depB;
}
I'm ok with this setup.
For me, the main benefits of using constructor injection is to inform the developer what are the external dependencies. I find it useful when writing unit test. When writing mocks, you just know what needs to be mocked.
An other benefit is to highlight when a Class has too many dependencies, it gives a hint that refactoring may be in order.
The alternative would be using setter injection (while keeping the informational aspect), but I've grown to enjoy constructor injection.
My answer is focusing about the "verbose and repetitive" part in your question; I let others decide how "correct" your usage of annotations is.
Even with Spring and its DI framework, in the end we are still talking about Java source code!
And in Java, if your base class only offers a constructor that takes some A and B; then of course your subclass has to make a call super(A a, B b); and of course, those values a and b have to come from somewhere!
So, what you call "verbose and repetitive" is a direct consequence of using Java.
In other words: there is no way to avoid that part!

Java inject implementation using TypeLiteral

I have a project that provides an interface, let's call it IImplementMe, which i want to inject into my project. This interface will be implemented by various producers, so I need to inject all implementations. I am trying to use TypeLiteral for this.
Here is the code of the producer :
#Singleton
public class SomeImplementation implements IImplementMe {
private final String value;
#Inject
public SomeImplementation(final SomeOtherConfig configuration) {
this.value= configuration.getValue();
}
#Override
public String getValue() {
return value;
}
}
And in my registry class I have register(IImplementMe.class).to(SomeImplementation.class);
Then, in my project I inject it like this :
#Inject
public SomeEndpoint(final List<IImplementMe> implementations){
///
}
and i bind it like
private static class MarketDataSetTypeLiteral extends TypeLiteral<List<IImplementMe>> {
}
bind(new MarketDataSetTypeLiteral()).toRegistry();
I made sure my SomeIMplementation constructor gets called, but in my endpoint the List is empty, so no implementation is provided. I'm using guice for injection. Any ideas ?
LE: It turns out that the provided implementation is created after my endpoint class is created (at creation time it injects a reference of an empty list). Later in the lifecycle the reference is updated with the implementation, so I actually have access to it after guice does it's stuff.
I'm guessing it's due to the maven dependencies, and how guice handles the instantiations. Since the producer must have a dependency on my project, I guess it makes sense it gets instantiated last, thus causing my initial problem.
You are looking for multibindings -> https://github.com/google/guice/wiki/Multibindings
public class IImplementMeModule extends AbstractModule {
public void configure() {
Multibinder< IImplementMe > uriBinder = Multibinder.newSetBinder(binder(), IImplementMe.class);
uriBinder.addBinding().to(SomeImplementationOfIImplementMe.class);
uriBinder.addBinding().to(AnotherImplementationOfIImplementMe.class);
... // bind plugin dependencies, such as our Flickr API key
}
}
Then you can inject the set of IImplemetnMe as following
#Inject TweetPrettifier(Set<IImplemetnMe> implementations)
I would suggest you to have a look at MapBindings which allows you provide keys for each implementation and then you will be able to inject your bindings as a Map

How to inject implementations from another module

I'm having a project based on Dagger 2 which consists of two modules. The core module includes some interfaces and some classes that have member injections declared for these interfaces.
The actual implementations of these interfaces are included in the second module which is an Android project. So, naturally the provide methods for these are included in the Android project.
Dagger will complain during compilation about not knowing how to inject these in the core module.
Any thoughts on how to achieve this without using constructor injections?
In short, I just tried this, and it works. Be sure to check the exact error messages and make sure you are providing these interfaces and #Inject annotations are present.
There is probably just some wrong named interface or a missing annotation. Following up is a full sample using your described architecture that is compiling just fine. The issue you are currently experiencing is probably the one described in the last part of this post. If possible, you should go with the first solution though and just add those annotations.
The library
For reproducability this sample has minimalist models. First, the interface needed by my class in the library module:
public interface MyInterface {
}
Here is my class that needs that interface. Make sure to declare it in the constructor and provide the #Inject annotation!
#MyScope // be sure to add scopes in your class if you use constructor injection!
public class MyClassUsingMyInterface {
private MyInterface mMyInterface;
#Inject
public MyClassUsingMyInterface(MyInterface myInterface) {
mMyInterface = myInterface;
}
}
The idea is that the interface will be implemented by the app using MyClassUsingMyInterface and provided by dagger. The code is nicely decoupled, and my awesome library with not so many features is complete.
The application
Here need to supply the actual coupling. This means to get MyClassUsingMyInterface we have to make sure we can supply MyInterface. Let's start with the module supplying that:
#Module
public class MyModule {
#Provides
MyInterface providesMyInterface() {
return new MyInterface() {
// my super awesome implementation. MIT license applies.
};
}
}
And to actually use this, we provide a component that can inject into MyTestInjectedClass that is going to need MyClassUsingMyInterface.
#Component(modules = MyModule.class)
public interface MyComponent {
void inject(MyTestInjectedClass testClass);
}
Now we have a way to provide the requested interface. We declared that interface needed by the library class in a constructor marked with #Inject. Now I want a class that requires my awesome library class to use. And I want to inject it with dagger.
public class MyTestInjectedClass {
#Inject
MyClassUsingMyInterface mMyClassUsingMyInterface;
void onStart() {
DaggerMyComponent.create().inject(this);
}
}
Now we hit compile...and dagger will create all the factories needed.
Inject Libraries you can not modify
To just provide the full scale of dagger, this sample could also have been without actual access to the source code of the library. If there is no #Inject annotation dagger will have a hard time creating the object. Notice the missing annotation:
public class MyClassUsingMyInterface {
private MyInterface mMyInterface;
public MyClassUsingMyInterface(MyInterface myInterface) {
mMyInterface = myInterface;
}
}
In that case we have to manually provide the class. The module would be needed to be modified like the following:
#Module
public class MyModule {
#Provides
MyInterface providesMyInterface() {
return new MyInterface() {
};
}
#Provides
MyClassUsingMyInterface providesMyClass(MyInterface myInterface) {
return new MyClassUsingMyInterface(myInterface);
}
}
This introduces more code for us to write, but will make those classes available that you can not modify.

Is it more optimal from maintenance point of view to implement property injection vs constructor injection?

Let's say I have the following classes and dagger module
public class Base implements IBase {
private IDependency dependency; //IDependency is an interface
Base(IDependency dependency) {
this.dependency = dependency
}
}
public class SubClass extends Base implements ISubclass {
Base(IDependency dependency) {
super(dependency)
}
}
#Module
public class MyModule {
// Let's assume some other class use SubClass and requires this
#Provides
ISubclass providesSubclass(IDependency dependency) {
return new SubClass(dependency);
}
}
If I add a new parameter to Base constructor, I'll have to go to MyModule and modify provides method to include this new parameter (besides obviusly chaging Base and Subclass constuctors). It seems to me that using propery injection I don't have this problem since I'm not using any constructor.
My feeling is that I might be doing something wrong or I have some concept wrong. I prefer constructor injection over property injection but right now I have to add a constructor parameter to a base class used by 40 other classes and not only I have to modify those 40 classes constructors, I also have to modify modules to reflect new constructors parameters.
Am I missing something? Am I correct if I say that doing constructor injection I'll write much more less code and maintenance will be easier?
Yes, you are missing some awesome feature: You can still use constructor injection in this case! And you don't even have to write it yourself.
If all of the dependencies can be provided, dagger can and will create the object for you. Given that you can provide IDependency you just need to modify your code like the following:
public class SubClass extends Base implements ISubclass {
#Inject // Don't forget the annotation!
public Base(IDependency dependency) {
super(dependency)
}
}
#Module
public class MyModule {
#Provides
ISubclass providesSubclass(SubClass subclass) {
return subclass;
}
}
You provide the interface, yet you depend on your implementation to provide it. Dagger will resolve this, and you can merrily add as many parameters to the constructor as you like. (Apart from the obvious changes to the actual constructors you already pointed out)
Don't forget the #Inject annotation!

suppress a singleton constructor in java with powermock

I'm trying to unit-test some classes that make use of a Singleton class whose constructor does some things I can't (and shouldn't) do from the unit-test environment. My ideal scenario would be to end up with the constructor completely suppressed and then stub out the other member methods that my test classes invoke. My problem is that I can't seem to get the constructor suppressed.
My understanding of a way to solve this would be something like the following:
public class MySingleton extends AbstractSingletonParent {
public final static MySingleton Only = new MySingleton();
private MySingleton(){
super(someVar); // I want the super-class constructor to not be called
//
//more code I want to avoid
}
public Object stubbedMethod() {}
}
public class ClassToBeTested {
public void SomeMethod(){
Object o = MySingleton.Only.stubbedMethod();
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(MySingleton.class)
public class TestClass {
#Test
public void SomeTest() {
suppress(constructor(MySingleton.class));
mockStatic(MySingleton.class);
PowerMock.replay(MySingleton.class);
// invoke ClassToBeTested, etc
PowerMock.verify(MySingleton.class);
//make some assertions
}
}
Unfortunately during the createMock invocation, the MySingleton constructor is hit, and it still calls the super constructor.
Am I doing something silly? I found an example on the web doing almost exactly this, but it was using a deprecated suppressConstructor method. Despite the deprecation I tried that, too, to no avail...
Is what I'm trying to do possible? If so, what am I doing wrong?
*Edited version now works.
You need to annotate TestClass with the #PrepareForTest annotation so it has a chance to manipulate the bytecode of the singletons.
Also, the superclass ctor supression signature should include somevar's class; right now you're just suppressing the default ctor.
See the #PrepareForTest API docs. Here's a blog post with some more details as well.
FWIW, it's working for me:
#RunWith(PowerMockRunner.class)
#PrepareForTest({EvilBase.class, NicerSingleton.class})
public class TestEvil {
#Test
public void testEvil() {
suppress(constructor(EvilBase.class));
assertEquals(69, EvilBase.getInstance().theMethod());
}
#Test
public void testNice() {
suppress(constructor(EvilBase.class));
suppress(constructor(NicerSingleton.class));
assertEquals(42, NicerSingleton.getInstance().theMethod());
}
}
How about you set the instance field ('only' in your code) of your Singleton with an instance instantiated with the constructor you want (you can do all of this with the Reflection API or dp4j).
The motivating example of a dp4j publication discusses that.
I am not sure what is it that you are doing wrong. But on the design side, i can suggest you look into dependency injection i.e. DI.
For making your code testable, make use of DI. With DI you would pass the singleton class as an constructor argument to your test class. And now since you pass an argument, inside your test case you can create a custom implementation of the AbstractSingleton class and your test case should work fine.
With DI, your code will become more testable.

Categories