Dagger Dependency Injection Provider with Qualifier - java

I'd like to get a confirmation that: if two providers providing the same type of instance, one with qualifier and the other one without, would this work?
// Existing provider
#Singleton
#Provides
static MetricsCollectorFactory provideMetricsCollectorFactory(){}
// New one to be added
#Singleton
#Provides
#VersionBasedMetricsCollectorFactory
static MetricsCollectorFactory provideVersionBasedMetricsCollectorFactory(){}
For the following two cases, especially the TestClass1, will Dagger know which MetricsCollectorFactory to inject?
#Inject
TestClass1(MetricsCollectorFactory basicFactory)
#Inject
TestClass2(#VersionBasedMetricsCollectorFactory MetricsCollectorFactory basicFactory)

Yes, as on the Dagger dev guide, there are zero or one qualifier instances per key or binding, and absent is different than present.
However, from a readability perspective, you might consider avoiding letting the two coexist—particularly if your team is unfamiliar with Dagger. Your #VersionBasedMetricsCollectorFactory MetricsCollectorFactory might wind up as a field metricsCollectorFactory, which might cause an unfamiliar developer to inject a bare MetricsCollectorFactory instead of a desired #VersionBasedMetricsCollectorFactory MetricsCollectorFactory. In contrast, introducing an alternative like #Default MetricsCollectorFactory might be helpful, or at least would provide a useful compilation error to encourage a more careful reading of the injection key.

Related

How do I properly inject many services into Spring MVC controller?

I have created Spring MVC application that has 3 user types. I've created separate controllers for each of them. Now in each of them, I have to inject service classes so I have done it like this:
#Controller
#RequestMapping("teacher")
public class TeacherController {
#Autowired
private StudentService studentService;
#Autowired
private GradeService gradeService;
#Autowired
private SubjectService subjectService;
#Autowired
private StudentGroupService studentGroupService;
#Autowired
private NewsService newsService;
#GetMapping("/index")
public String indexPage(Model theModel) {
List<News> tempNewsList = newsService.getNews();
theModel.addAttribute("theNewList", tempNewsList);
return "teacher/index";
}
This code is using field injection. Which is, as I now learned, a solution that should be avoided and replaced with constructor injection. So I've Autowired a constructor with all of these fields like this:
#Autowired
public TeacherController(StudentService studentService, GradeService gradeService, SubjectService subjectService, StudentGroupService studentGroupService, NewsService newsService) {
this.studentService = studentService;
this.gradeService = gradeService;
this.subjectService = subjectService;
this.studentGroupService = studentGroupService;
this.newsService = newsService;
}
Is this a good solution, creating such verbose constructor in such simple code? And what if I had even more services in my code? Is this even acceptable or in this case should I refactor my code, e.g. delegate services to other services or create more controllers?
You answered this well yourself! Spring addresses exactly this concern in the docs here in the box titled Constructor-based or setter-based DI?:
The Spring team generally advocates constructor injection, as it lets
you implement application components as immutable objects and ensures
that required dependencies are not null. Furthermore,
constructor-injected components are always returned to the client
(calling) code in a fully initialized state. As a side note, a large
number of constructor arguments is a bad code smell, implying that the
class likely has too many responsibilities and should be refactored to
better address proper separation of concerns.
That is, you should ideally refactor. Used SOLID principles and think "what is the one job of the class I'm creating?".
In conclution, according to the documentation if exist many DI you can evaluate every one and try to use set based and/or contructor based. The documentations eplain which one to use below:
Constructor-based or setter-based DI?
Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the #Required annotation on a setter method can be used to make the property be a required dependency.
The Spring team generally advocates constructor injection, as it lets you implement application components as immutable objects and ensures that required dependencies are not null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.
Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection.
Use the DI style that makes the most sense for a particular class. Sometimes, when dealing with third-party classes for which you do not have the source, the choice is made for you. For example, if a third-party class does not expose any setter methods, then constructor injection may be the only available form of DI.

Does dependency injection mean no inline initialization?

If I follow dependency injection principle for a class design, I should make sure my class does not try to instantiate its dependencies within my class, but rather ask for the object through the constructor.
This way I am in control of the dependencies I provide for the class while unit-testing it. This I understand.
But what I am not sure is does this mean that a good class design which follows dependency injection principle means that its fields should never be initialized inline? Should we totally avoid inline initialization to produce testable code?
EDIT
Which is better 1 or 2?
1
public class Car {
private Tire tire = new Tire(); //
}
2
public class Car {
private Tire tire;
public Car(Tire tire) {
this.tire = tire
}
}
No, it surely doesn't mean inline initialization.
I'm not a Java user but this term is relevant to many programming languages.
Basically, instead of having your objects creating a dependency or asking a factory object to make one for them, you pass the needed dependencies into the object externally, and you make it somebody else's problem.
public SomeClass() {
myObject = Factory.getObject();
}
"Dependency Injection" is a 25-dollar term for a 5-cent concept. [...]
Dependency injection means giving an object its instance variables.
[...].
Dependency injection is basically providing the objects that an object needs (its dependencies) instead of having it construct them itself. It's a very useful technique for testing since it allows dependencies to be mocked or stubbed out.
Any application is composed of many objects that collaborate with each other to perform some useful stuff. Traditionally each object is responsible for obtaining its own references to the dependent objects (dependencies) it collaborates with. This leads to highly coupled classes and hard-to-test code.
A lot of reference from here
In my opinion, In general, if you think that the data field is a dependency, then let the dependency management container should manage it. What counts a dependency and what is not dependency is a tough question, and only you can decide.
For example: if your design of car allows working with different types of Tyres, then it's a dependency. Otherwise, inside a class Car you'll have to work with some kind of TyreFactory, which is not really reasonable.
If you work with DI container, testing the class will be a breeze. You'll have to provide a stub/mock to the class which is obviously a real benefit. So, in your example, if you go with the first solution then, how will you test that your car works with different types of Tyres?

Guice multiple annotations

I have an interface called StatsStore. I have 2 implementations of this store. An in-memory and an SQL implementation called InMemoryStatsStore and SqlStatsStore. In order to inject them I've create 2 annotations #InMemoryStore and #SqlStore. the injections are:
bind(StatsStore.class)
.annotatedWith(InMemoryStore.class)
.to(InMemoryStatsStore.class);
bind(StatsStore.class)
.annotatedWith(SqlStore.class)
.to(SqlStatsStore.class);
Now I want to add a new layer of annotation to separate between InMemoryStringStore and InMemoryNumberStore but I can't add more than one annotation to the binding lines e.g. the following does not compile:
bind(StatsStore.class)
.annotatedWith(InMemoryStore.class)
.annotatedWith(NumberStoreAnnotation.class) // using named doesn't work as well
.to(InMemoryNumberStore.class);
How can I add more than one annotation without using a single named one which would be quite complicated the more layers I add to it?
The other solution I had in mind is Injecting twice:
bind(StatsStore.class)
.annotatedWith(InMemoryStore.class)
.to(InMemoryStatsStore.class);
bind(InMemoryStatsStore.class)
.annotatedWith(NumberStoreAnnotation.class)
.to(InMemoryNumberStore.class);
Thanks all.
As Amit said, you can't have more than one #BindingAnnotation apply to any given injection. Internally, Guice works like a Map<Key, Provider> where a Key is a possibly-parameterized class with an optional single annotation instance. However, because these are instances, you're welcome to create your own instantiable annotation that works the way Named works.
#Inject #InMemoryStore(NUMBER) StatsStore inMemoryNumberStore;
#Inject #SqlStore(STRING) StatsStore sqlStringStore;
// or
#Inject #Store(dataType=NUMBER, backend=SQL) sqlNumberStore;
The annotation must have the fields defined like so. (If you have one element named value, you can omit the property name per JLS 9.7.3.) Equal annotations are defined as in the Annotation.equals docs.
public enum DataType { NUMBER, STRING; }
public enum Backend { SQL, IN_MEMORY; }
#BindingAnnotation #Retention(SOURCE) #Target({ FIELD, PARAMETER, METHOD })
public #interface Store {
DataType dataType();
Backend backend();
}
That works nicely for #Provides, when you can invoke the annotation the same way you inject it, but how can you create a factory method for instances like Names.named? For that, you'll need to do one of the following:
Create an anonymous implementation, with accessors for each attribute as well as correct implementations of equals and hashCode. Note that the hashCode contract is much stricter than for Object, but you can get compatible implementations from Apache annotation utils or similar libraries.
Use AnnotationLiteral, which provides equals and hashCode implementations for arbitrary subclasses.
Use Google Auto or a similar code generator to generate code for a compatible implementation for you. Familiarity with this type of solution is particularly useful for Android and other memory-constrained environments for which reflection is slow, though such environments usually preclude you from using Guice. (#Qualifier annotations work the same way in other JSR-330 compatible dependency injection frameworks, though, including Dagger.)
If the above seems a little complicated, or if you want more complex logic than Guice's map-based implementation can accomplish, one alternative is to add a layer of indirection that you control:
public class StoreStore {
#Inject Provider<InMemoryNumberStore> inMemoryNumberStoreProvider;
// ...
// You can also inject the Injector to call getInstance with a class literal.
public StatsStore getStore(DataType dataType, Backend backend) {
// This can also be a switch or any other sort of lookup, of course.
if (dataType == NUMBER && backend == IN_MEMORY) {
return inMemoryNumberStoreProvider.get();
} // ...
}
}
You can't do that:
#BindingAnnotation tells Guice that this is a binding annotation. Guice will produce an error if ever multiple binding annotations apply to the same member.
You could use named bindings instead, or you should consider redesigning your solution.

Can someone explain what com.google.inject does?

I've seen a class declared with its only constructor being annotated with #Inject.
And I don't see the one constructor being called anywhere in the entire project.
So two questions:
<1> What does #Inject mean? (What does it do? Why is the constructor being annotated with it?)
<2> As mentioned, the constructor never gets called directly, does that have anything to do with the fact that it is annotated with #Inject?
Google Guice is a dependency injection library that allows you to construct objects simply by declaring relationships between them. Objects are constructed as they are demanded to construct other objects. You can also implement abstract classes or interfaces with different implementations by configuring Guice, which makes it very useful for running or testing your code.
#Inject annotates constructors and methods that determine what an object needs to be initialized. There are also a lot of other annotations that determine how Guice works. But simply annotating objects isn't enough; you also have to configure them with Guice bindings.
Here's a really simple example (from one of my applications). I have a MySQLDataTracker that requires a MysqlConnectionPoolDataSource:
public class MySQLDataTracker extends ExperimentDataTracker {
#Inject
public MySQLDataTracker(MysqlConnectionPoolDataSource ds) {
....
}
}
Note that MySQLDataTracker extends ExperimentDataTracker, an abstract class that can be implemented several ways. In my Guice bindings I declare that
bind(ExperimentDataTracker.class).to(MySQLDataTracker.class);
This declares that whenever I want an ExperimentDataTracker, a MySQLDataTracker will be constructed. I also need to make sure that the requisite object for constructing this is available, so I declare a provider:
#Provides #Singleton
MysqlConnectionPoolDataSource getMysqlCPDS() {
return (some thingy I construct...);
}
This says that there should only be a single connection pool data source. It also means that when I try to get an instance of ExperimentDataTracker, Guice has everything it needs to construct it. If I didn't have the above, it would throw an error.
ExperimentDataTracker tracker = injector.getInstance(ExperimentDataTracker.class);
However, it doesn't stop here. Other things depend on the ExperimentDataTracker, so it's used in turn to inject other objects. At the top level of my code there is actually only one call to getInstance, which makes Guice construct pretty much everything. I don't have to write the new statement anywhere.
I'm a big fan of Guice after seeing how it reduced the need for me to initialize a bunch of objects in order to initialize other objects. Basically I just ask for the object I want, and poof! it appears.

array dependency injection in spring?

is there a way to use dependency injection to inject all available implementations of a specific interface in spring?
This is kind of the same thing as asked here for .NET.
Though my aim is to use #Autowired for this:
public class Foo{
#Autowired
private IDataCollector[] collectors;
}
Is this supported, would this require hacking or should I preferably use another component where all implementations of IDataCollector register themselve and use that accessor component with autowired instead of the array injection?
A reason I can think of why this may not be implemented per default may be, that it would also inject possible mock implementations where inappropriate. Though I'm still interested wether this is possible or not. :)
you can inject a List and Spring will convert this for you:
<util:list id="collectors">
<value>someone#something.com</value>
<value>someoneelse#something.com</value>
</util:list>
Your example should work fine, as should List<IDataCollector>. Did you give it a try before asking, and found it didn't work?
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-autowired-annotation
It is also possible to provide all
beans of a particular type from the
ApplicationContext by adding the
annotation to a field or method that
expects an array of that type.

Categories

Resources