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.
Related
Let's say
I have integration tests, therefore there is an ApplicationContextIntegrationTests class that contains dummy beans (dependencies on other services) for initializing the app context for integration profile like this:
#Bean
public MyService myService(Proc proc) {
return new MyServiceImp();
}
I have an interface MyInterfaceA with 20 methods (the code is autogenerated based on the definition in api.yaml), I cannot implement it and I don't have access to the implementation. This interface (well, it is an implementation) also should be inserted in the application context. Obviously, I need to implement all interface methods in order to insert that bean and it leads to messy code with default methods implementations on 50 lines. Moreover, I need to insert 3 interfaces.
Is there a way to avoid that huge amount of code?
I have found that Lombok provides a #Delegate annotation which is used in similar situations, but it is appliable only on fields, whereas I need to deal with methods (bcs of #Bean).
Is this generated class that implements MyInterfaceA also a bean? If so, you can use #MockBean to mock its implementation in the test. This way, wherever a bean of type MyInterfaceA is used, the mock will be injected in its place, and you can have the mock do whatever you want.
In my Spring boot app i'm creating a Factory for creating different objects with the same interface and dependency like below.
#Component
public class FarmFactory {
#Autowired
private FarmRepo farmRepo;
public IFarm create(FarmType type) {
if (type == type.APPLE) {
return new AppleFarm(farmRepo);
} else if (type == type.ANIMAL) {
return new AnimalFarm(farmRepo);
} else {
return new EmptyFarm(farmRepo);
}
}
}
I was wondering if it was better to limit the scope the FarmRepo dependency by instead injecting it into each subclass of farm (apple, animal, empty). Or if it was better to keep a single dependency in a higher scope of the Factory.
Alternatively the dependency FarmRepo could be passed into the create method with the type, but not sure what the rule of thumb is for dependency scope.
According to my experience, a good design can reduce if-else as much as possible. So I prefer to injecting it into each subclass in your case. Thus in future, you have more flexibility if the dependency also have subclass as well.
I suggest to create named beans of your real implementations (AppleFarm, AnimalFarm ..) and inject the FarmRepo. With you factory your real implementations won't be managed by Spring (no beans).
#Component("appleFarm")
#RequiredArgsConstructor <- this is a Lombok feature check it out
public class AppleFarm implements Farm {
private final FarmRepo repo;
...
}
I assume your IFarm implementations are model classes. It is not a good practise to have a repository inside a model. You should consider to move the creation of different IFarm implementations to the FarmRepo.
If IFarm implementations are some sort of service classes that governs business logic then you should let spring handle it injecting the FarmRepo instance to them. In that case you better consider having an abstract class rather than using IFarm, because FarmRepo is a common dependency among them.
There is nothing wrong in employing a simple factory method to instantiate the required runtime type, if that's required, it needs to be done somewhere, it helps you gain a valid design in terms of OCP (open close principle) preventing you to change bahaviour depending on type parameter, rather you make use of polymorphism.
I am new to Guice. Is constructor injection preferred or field injection preferred?
Field injection appears to be quick and simple but testing would be a challenge as constructor is missing.
Thanks.
Use constructor injection
On their Minimize mutability wiki page, the Guice team says:
Minimize mutability
Wherever possible, use constructor injection to create immutable objects. Immutable objects are simple, shareable, and can be composed. Follow this pattern to define your injectable types:
[...]
Injecting methods and fields
Constructor injection has some limitations:
Injected constructors may not be optional.
It cannot be used unless objects are created by Guice. This is a dealbreaker for certain frameworks.
Subclasses must call super() with all dependencies. This makes constructor injection cumbersome, especially as the injected base class changes.
Method injection is most useful when you need to initialize an instance that is not constructed by Guice. Extensions like AssistedInject and Multibinder use method injection to initialize bound objects.
Field injection has the most compact syntax, so it shows up frequently on slides and in examples. It is neither encapsulated nor testable. Never inject final fields; the JVM doesn't guarantee that the injected value will be visible to all threads.
Would like to point out some differences so you can decide for yourself:
With constructor injection you can use the final modifier. Can't do that with field injection. Advantages of final members are off-topic and you can read up on that.
Writing test cases with constructor injection is easy (like you already mentioned)
With constructor injection all dependencies are mandatory. In order to declare a class you would need to know all its required dependencies.
With field injection, you will hide your dependencies for the class instead of making them explicit.
Above are just a few points to think about. I personally prefer Constructor Injection because of ease of testing and final support.
Both the types are fine. But you need to know when and where you need to use constructor injection.
Advantages of Constructor injection are,
It Provides Immutability (If used Properly)
In Constructor Injection you can use something like this.
public class MemberResource {
private final IMemberService memberService;
#Inject
public MemberResource(IMemberService memberService) {
this.memberService = memberService;
}
}
Unit testing becomes easier.
Advantage of Field injection is less coding.
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.
I couldn't find any reasonable answer here on SO so I hope it's not a duplicate. So why should I prefer setter or constructor injection over simple
#Inject
MyBean bean;
I get the usage of the constructor injection if you need to do something with injected bean during your class initialization like
public void MyBean(#Inject OtherBean bean) {
doSomeInit(bean);
//I don't need to use #PostConstruct now
}
but still, it's almost the same like #PostConstruct method and I don't get setter injection at all, isn't it just a relic after Spring and other DI frameworks?
Constructor and property injection gives you the option to initialize the object even in a non CDI environment easily, e.g a unit test.
In a non-CDI environment you can still simply use the object by just passing the constructor arg.
OtherBean b = ....;
new MyBean(b);
If you just use field injection you usually must use reflection to access the field, because fields are usually private.
If you use property injection you can also write code in the setter. E.g. validation code or you clear internal caches that hold values which are derived from the property that the setter modifies. What you want to do depends on your implementation needs.
Setter vs constructor injection
In object-oriented programming an object must be in a valid state after construction and every method invocation changes the state to another valid state.
For setter injection this means that you might require a more complex state handling, because an object should be in a valid state after construction, even if the setter has not been invoked yet. Thus the object must be in a valid state even if the property is not set. E.g. by using a default value or a null object.
If you have a dependency between the object's existence and the property, the property should either be a constructor argument. This will also make the code more clean, because if you use a constructor parameter you document that the dependency is necessary.
So instead of writing a class like this
public class CustomerDaoImpl implements CustomerDao {
private DataSource dataSource;
public Customer findById(String id){
checkDataSource();
Connection con = dataSource.getConnection();
...
return customer;
}
private void checkDataSource(){
if(this.dataSource == null){
throw new IllegalStateException("dataSource is not set");
}
}
public void setDataSource(DataSource dataSource){
this.dataSource = dataSource;
}
}
you should either use constructor injection
public class CustomerDaoImpl implements CustomerDao {
private DataSource dataSource;
public CustomerDaoImpl(DataSource dataSource){
if(dataSource == null){
throw new IllegalArgumentException("Parameter dataSource must not be null");
}
this.dataSource = dataSource;
}
public Customer findById(String id) {
Customer customer = null;
// We can be sure that the dataSource is not null
Connection con = dataSource.getConnection();
...
return customer;
}
}
My conclusion
Use properties for every optional dependency.
Use constructor args for every mandatory dependency.
PS: My blog The difference between pojos and java beans explains my conclusion in more detail.
EDIT
Spring also suggests to use constructor injection as I found in the spring documentation, section Setter-based Dependency Injection.
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.
Constructor injection is also a better way when you think about unit tests, because it is easier to call the constructor instead of setting private (#Autowired) fields.
When using CDI, there is no reason whatsoever to use constructor or setter injection. As noted in the question, you add a #PostConstruct method for what would otherwise be done in a constructor.
Others may say that you need to use Reflection to inject fields in unit tests, but that is not the case; mocking libraries and other testing tools do that for you.
Finally, constructor injection allows fields to be final, but this isn't really a disadvantage of #Inject-annotated fields (which can't be final). The presence of the annotation, combined with the absence of any code explicitly setting the field, should make it clear it is to be set by the container (or testing tool) only. In practice, no one will be re-assigning an injected field.
Constructor and setter injection made sense in the past, when developers usually had to manually instantiate and inject dependencies into a tested object. Nowadays, technology has evolved and field injection is a much better option.
Accepted answer is great, however it doesn't give credit to the main advantage of constructor injection - class immutability, which helps to achieve thread-safety, state safety, and better readability on the classes.
Consider you have class with dependencies and all of those dependencies are provided as constructor arguments, then you can know that the object will never exist in a state where dependencies are invalid. There is no need for setters for those dependencies (as long as they are private), so the object is instantiated to a full state or is not instantiated at all.
An immutable object is much more likely to well behave in an multithreaded application. Although the class still needs to be made internally thread-safe, you don't have to worry about external clients coordinating access to the object.
Of course this can be usefull only in certain scenarios. Setter injection is great for partial depencdency, where for example we have 3 properties in a class and 3 arg constructor and setters methods. In such case, if you want to pass information for only one property, it is possible by setter method only. Very useful for testing purposes.